├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── bind_network_card.sh ├── config.conf ├── igb_uio ├── .built-in.o.cmd ├── .igb_uio.ko.cmd ├── .igb_uio.mod.o.cmd ├── .igb_uio.o.cmd ├── .tmp_versions │ └── igb_uio.mod ├── Kbuild ├── Makefile ├── Module.symvers ├── built-in.o ├── compat.h ├── igb_uio.c ├── igb_uio.ko ├── igb_uio.mod.c ├── igb_uio.mod.o ├── igb_uio.o └── modules.order ├── readme.md ├── src ├── config.h ├── core_dpdk.cpp ├── core_dpdk.h ├── decode.cpp ├── decode.h ├── flow.h ├── flowCache.h ├── help.h ├── log.cpp ├── log.h ├── main.cpp ├── protocol.h ├── thread.cpp └── thread.h ├── thirdpart └── spdlog │ ├── async.h │ ├── async_logger-inl.h │ ├── async_logger.h │ ├── cfg │ ├── argv.h │ ├── env.h │ ├── helpers-inl.h │ └── helpers.h │ ├── common-inl.h │ ├── common.h │ ├── details │ ├── backtracer-inl.h │ ├── backtracer.h │ ├── circular_q.h │ ├── console_globals.h │ ├── file_helper-inl.h │ ├── file_helper.h │ ├── fmt_helper.h │ ├── log_msg-inl.h │ ├── log_msg.h │ ├── log_msg_buffer-inl.h │ ├── log_msg_buffer.h │ ├── mpmc_blocking_q.h │ ├── null_mutex.h │ ├── os-inl.h │ ├── os.h │ ├── periodic_worker-inl.h │ ├── periodic_worker.h │ ├── registry-inl.h │ ├── registry.h │ ├── synchronous_factory.h │ ├── tcp_client-windows.h │ ├── tcp_client.h │ ├── thread_pool-inl.h │ ├── thread_pool.h │ ├── udp_client-windows.h │ ├── udp_client.h │ └── windows_include.h │ ├── fmt │ ├── bin_to_hex.h │ ├── bundled │ │ ├── args.h │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── fmt.license.rst │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── locale.h │ │ ├── os.h │ │ ├── ostream.h │ │ ├── printf.h │ │ ├── ranges.h │ │ └── xchar.h │ ├── chrono.h │ ├── compile.h │ ├── fmt.h │ ├── ostr.h │ ├── ranges.h │ └── xchar.h │ ├── formatter.h │ ├── fwd.h │ ├── libspdlog.a │ ├── logger-inl.h │ ├── logger.h │ ├── pattern_formatter-inl.h │ ├── pattern_formatter.h │ ├── sinks │ ├── android_sink.h │ ├── ansicolor_sink-inl.h │ ├── ansicolor_sink.h │ ├── base_sink-inl.h │ ├── base_sink.h │ ├── basic_file_sink-inl.h │ ├── basic_file_sink.h │ ├── daily_file_sink.h │ ├── dist_sink.h │ ├── dup_filter_sink.h │ ├── hourly_file_sink.h │ ├── mongo_sink.h │ ├── msvc_sink.h │ ├── null_sink.h │ ├── ostream_sink.h │ ├── qt_sinks.h │ ├── ringbuffer_sink.h │ ├── rotating_file_sink-inl.h │ ├── rotating_file_sink.h │ ├── sink-inl.h │ ├── sink.h │ ├── stdout_color_sinks-inl.h │ ├── stdout_color_sinks.h │ ├── stdout_sinks-inl.h │ ├── stdout_sinks.h │ ├── syslog_sink.h │ ├── systemd_sink.h │ ├── tcp_sink.h │ ├── udp_sink.h │ ├── win_eventlog_sink.h │ ├── wincolor_sink-inl.h │ └── wincolor_sink.h │ ├── spdlog-inl.h │ ├── spdlog.h │ ├── stopwatch.h │ ├── tweakme.h │ └── version.h └── unbind_all_network_card.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /log 2 | /test 3 | /.vscode 4 | /build 5 | /install.md 6 | note.md 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0) 2 | 3 | PROJECT(Qcap VERSION 0.1.0)#设置工程名称和版本 4 | SET(CMAKE_BUILD_TYPE "Debug")#设置编译模式为debug版本,可以gdb调试 5 | 6 | SET (CMAKE_CXX_STANDARD 17) 7 | #asan编译选项暂时无法运行 8 | #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-recover=address -fno-omit-frame-pointer -fsanitize=leak -fsanitize=undefined") 9 | MESSAGE(STATUS "PROJECT_BINARY_DIR = " ${PROJECT_BINARY_DIR})#输出提示信息,二进制文件的目录 10 | MESSAGE(STATUS "PROJECT_SOURCE_DIR = " ${PROJECT_SOURCE_DIR})#输出提示信息,工程文件的目录 11 | MESSAGE(STATUS "CMAKE_SOURCE_DIR = " ${CMAKE_SOURCE_DIR})#输出提示信息,工程文件的目录 12 | 13 | INCLUDE_DIRECTORIES(/usr/local/include)#添加头文件搜索目录 14 | INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/thirdpart) #包含spdlog的头文件 15 | 16 | find_package(PkgConfig REQUIRED) 17 | pkg_check_modules(dpdk REQUIRED IMPORTED_TARGET libdpdk) 18 | 19 | file(GLOB_RECURSE SRC_DIR_LIST "./src/*.cpp") 20 | # add the executable 21 | add_executable(Qcap ${SRC_DIR_LIST}) #添加可执行文件 22 | 23 | target_link_libraries(Qcap PRIVATE PkgConfig::dpdk ${CMAKE_THREAD_LIBS_INIT}) 24 | target_link_libraries(Qcap PRIVATE stdc++fs) 25 | target_link_libraries(Qcap PRIVATE pthread) -------------------------------------------------------------------------------- /bind_network_card.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 检查是否传递了网卡名参数 3 | network_card=$1 4 | if [ -z "$network_card" ]; then 5 | echo "Missing parameter. Please provide the network card name. eg dpdk-igb_uio-init.sh ens256" 6 | exit 1 7 | fi 8 | 9 | echo -e "\e[34m*** dpdk igb_uio mode preoperational environment initialization ***\e[0m" 10 | export RTE_SDK=/home/dpdk/dpdk-stable-21.11.2 11 | export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig 12 | export LD_LIBRARY_PATH=/usr/local/lib64 13 | 14 | echo -e "\e[32m RTE_SDK = ${RTE_SDK} \e[0m" 15 | echo -e "\e[32m PKG_CONFIG_PATH = ${PKG_CONFIG_PATH} \e[0m" 16 | echo -e "\e[32m LD_LIBRARY_PATH = ${LD_LIBRARY_PATH} \e[0m" 17 | 18 | 19 | 20 | #down掉网卡 21 | ifconfig $network_card down 22 | 23 | #插入igb模块 24 | modprobe uio 25 | insmod ./igb_uio/igb_uio.ko 26 | depmod 27 | modprobe igb_uio 28 | 29 | output=$(/home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --status) 30 | 31 | # 解析输出内容,获取包含"if="的行,并提取满足条件的行首的第一串字符 32 | regex="^([0-9a-fA-F:.]+) .+if=${network_card}" 33 | result="" 34 | while IFS= read -r line; do 35 | if [[ $line =~ $regex ]]; then 36 | result="${BASH_REMATCH[1]}" 37 | break 38 | fi 39 | done <<< "$output" 40 | 41 | 42 | /home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --bind=igb_uio $result 43 | /home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --status 44 | 45 | # ens224: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 46 | # link/ether 00:0c:29:c8:8b:f5 brd ff:ff:ff:ff:ff:ff 47 | # inet 192.168.182.129/24 brd 192.168.182.255 scope global noprefixroute dynamic ens224 48 | # valid_lft 5183695sec preferred_lft 5183695sec 49 | # inet6 fe80::7604:5b24:26ee:c96a/64 scope link noprefixroute 50 | # valid_lft forever preferred_lft forever 51 | # ens256: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 52 | # link/ether 00:0c:29:c8:8b:eb brd ff:ff:ff:ff:ff:ff 53 | # inet 192.168.182.140/24 brd 192.168.182.255 scope global noprefixroute dynamic ens256 54 | # valid_lft 5183695sec preferred_lft 5183695sec 55 | # inet6 fe80::9d31:a388:41cc:9470/64 scope link noprefixroute 56 | # valid_lft forever preferred_lft forever 57 | 58 | # 0000:02:00.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=ens32 drv=e1000 unused=igb_uio *Active* 59 | # 0000:02:02.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=ens34 drv=e1000 unused=igb_uio *Active* 60 | # 0000:02:03.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=ens35 drv=e1000 unused=igb_uio *Active* 61 | # 0000:02:04.0 '82545EM Gigabit Ethernet Controller (Copper) 100f' if=ens36 drv=e1000 unused=igb_uio *Active* -------------------------------------------------------------------------------- /config.conf: -------------------------------------------------------------------------------- 1 | # decodeMode: 2 | # 1 单包解码 3 | # 2 会话解码 4 | # flowOuttime 单位ms 5 | # readTimeFlushLog 是否实时输出日志 6 | # isPromiscuous 是否打开混杂模式 7 | decodeMode = 1 8 | flowOutTime = 30000 9 | logLevel = info 10 | realTimeFlushLog = true 11 | isPromiscuous = true -------------------------------------------------------------------------------- /igb_uio/.built-in.o.cmd: -------------------------------------------------------------------------------- 1 | cmd_/home/dpdk-kmods/linux/igb_uio/built-in.o := rm -f /home/dpdk-kmods/linux/igb_uio/built-in.o; ar rcsD /home/dpdk-kmods/linux/igb_uio/built-in.o 2 | -------------------------------------------------------------------------------- /igb_uio/.igb_uio.ko.cmd: -------------------------------------------------------------------------------- 1 | cmd_/home/dpdk-kmods/linux/igb_uio/igb_uio.ko := ld -r -m elf_x86_64 -T ./scripts/module-common.lds --build-id -o /home/dpdk-kmods/linux/igb_uio/igb_uio.ko /home/dpdk-kmods/linux/igb_uio/igb_uio.o /home/dpdk-kmods/linux/igb_uio/igb_uio.mod.o 2 | -------------------------------------------------------------------------------- /igb_uio/.tmp_versions/igb_uio.mod: -------------------------------------------------------------------------------- 1 | /home/dpdk-kmods/linux/igb_uio/igb_uio.ko 2 | /home/dpdk-kmods/linux/igb_uio/igb_uio.o 3 | -------------------------------------------------------------------------------- /igb_uio/Kbuild: -------------------------------------------------------------------------------- 1 | ccflags-y := $(MODULE_CFLAGS) 2 | obj-m := igb_uio.o 3 | -------------------------------------------------------------------------------- /igb_uio/Makefile: -------------------------------------------------------------------------------- 1 | KSRC ?= /lib/modules/$(shell uname -r)/build 2 | 3 | all: 4 | make -C $(KSRC)/ M=$(CURDIR) 5 | 6 | %: 7 | make -C $(KSRC)/ M=$(CURDIR) $@ 8 | -------------------------------------------------------------------------------- /igb_uio/Module.symvers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgpp-programer/Qcap/873ed95b9bec2d25cef0e31aa14d0bca86a745d0/igb_uio/Module.symvers -------------------------------------------------------------------------------- /igb_uio/built-in.o: -------------------------------------------------------------------------------- 1 | ! 2 | -------------------------------------------------------------------------------- /igb_uio/compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Minimal wrappers to allow compiling igb_uio on older kernels. 4 | */ 5 | 6 | #ifndef RHEL_RELEASE_VERSION 7 | #define RHEL_RELEASE_VERSION(a, b) (((a) << 8) + (b)) 8 | #endif 9 | 10 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) 11 | #define pci_cfg_access_lock pci_block_user_cfg_access 12 | #define pci_cfg_access_unlock pci_unblock_user_cfg_access 13 | #endif 14 | 15 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) 16 | #define HAVE_PTE_MASK_PAGE_IOMAP 17 | #endif 18 | 19 | #ifndef PCI_MSIX_ENTRY_SIZE 20 | #define PCI_MSIX_ENTRY_SIZE 16 21 | #define PCI_MSIX_ENTRY_VECTOR_CTRL 12 22 | #define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 23 | #endif 24 | 25 | /* 26 | * for kernels < 2.6.38 and backported patch that moves MSI-X entry definition 27 | * to pci_regs.h Those kernels has PCI_MSIX_ENTRY_SIZE defined but not 28 | * PCI_MSIX_ENTRY_CTRL_MASKBIT 29 | */ 30 | #ifndef PCI_MSIX_ENTRY_CTRL_MASKBIT 31 | #define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 32 | #endif 33 | 34 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) && \ 35 | (!(defined(RHEL_RELEASE_CODE) && \ 36 | RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5, 9))) 37 | 38 | static int pci_num_vf(struct pci_dev *dev) 39 | { 40 | struct iov { 41 | int pos; 42 | int nres; 43 | u32 cap; 44 | u16 ctrl; 45 | u16 total; 46 | u16 initial; 47 | u16 nr_virtfn; 48 | } *iov = (struct iov *)dev->sriov; 49 | 50 | if (!dev->is_physfn) 51 | return 0; 52 | 53 | return iov->nr_virtfn; 54 | } 55 | 56 | #endif /* < 2.6.34 */ 57 | 58 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \ 59 | (!(defined(RHEL_RELEASE_CODE) && \ 60 | RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 4))) 61 | 62 | #define kstrtoul strict_strtoul 63 | 64 | #endif /* < 2.6.39 */ 65 | 66 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) && \ 67 | (!(defined(RHEL_RELEASE_CODE) && \ 68 | RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 3))) 69 | 70 | /* Check if INTX works to control irq's. 71 | * Set's INTX_DISABLE flag and reads it back 72 | */ 73 | static bool pci_intx_mask_supported(struct pci_dev *pdev) 74 | { 75 | bool mask_supported = false; 76 | uint16_t orig, new; 77 | 78 | pci_block_user_cfg_access(pdev); 79 | pci_read_config_word(pdev, PCI_COMMAND, &orig); 80 | pci_write_config_word(pdev, PCI_COMMAND, 81 | orig ^ PCI_COMMAND_INTX_DISABLE); 82 | pci_read_config_word(pdev, PCI_COMMAND, &new); 83 | 84 | if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { 85 | dev_err(&pdev->dev, "Command register changed from " 86 | "0x%x to 0x%x: driver or hardware bug?\n", orig, new); 87 | } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) { 88 | mask_supported = true; 89 | pci_write_config_word(pdev, PCI_COMMAND, orig); 90 | } 91 | pci_unblock_user_cfg_access(pdev); 92 | 93 | return mask_supported; 94 | } 95 | 96 | static bool pci_check_and_mask_intx(struct pci_dev *pdev) 97 | { 98 | bool pending; 99 | uint32_t status; 100 | 101 | pci_block_user_cfg_access(pdev); 102 | pci_read_config_dword(pdev, PCI_COMMAND, &status); 103 | 104 | /* interrupt is not ours, goes to out */ 105 | pending = (((status >> 16) & PCI_STATUS_INTERRUPT) != 0); 106 | if (pending) { 107 | uint16_t old, new; 108 | 109 | old = status; 110 | if (status != 0) 111 | new = old & (~PCI_COMMAND_INTX_DISABLE); 112 | else 113 | new = old | PCI_COMMAND_INTX_DISABLE; 114 | 115 | if (old != new) 116 | pci_write_config_word(pdev, PCI_COMMAND, new); 117 | } 118 | pci_unblock_user_cfg_access(pdev); 119 | 120 | return pending; 121 | } 122 | 123 | #endif /* < 3.3.0 */ 124 | 125 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) 126 | #define HAVE_PCI_IS_BRIDGE_API 1 127 | #endif 128 | 129 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) 130 | #define HAVE_MSI_LIST_IN_GENERIC_DEVICE 1 131 | #endif 132 | 133 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) 134 | #define HAVE_PCI_MSI_MASK_IRQ 1 135 | #endif 136 | 137 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) 138 | #define HAVE_ALLOC_IRQ_VECTORS 1 139 | #endif 140 | 141 | static inline bool igbuio_kernel_is_locked_down(void) 142 | { 143 | #ifdef CONFIG_LOCK_DOWN_KERNEL 144 | #ifdef CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT 145 | return kernel_is_locked_down(NULL); 146 | #elif defined(CONFIG_EFI_SECURE_BOOT_LOCK_DOWN) 147 | return kernel_is_locked_down(); 148 | #else 149 | return false; 150 | #endif 151 | #else 152 | return false; 153 | #endif 154 | } 155 | 156 | #ifndef fallthrough 157 | 158 | #ifndef __has_attribute 159 | #define __has_attribute(x) 0 160 | #endif 161 | 162 | #if __has_attribute(__fallthrough__) 163 | #define fallthrough __attribute__((__fallthrough__)) 164 | #else 165 | #define fallthrough do {} while (0) /* fallthrough */ 166 | #endif 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /igb_uio/igb_uio.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgpp-programer/Qcap/873ed95b9bec2d25cef0e31aa14d0bca86a745d0/igb_uio/igb_uio.ko -------------------------------------------------------------------------------- /igb_uio/igb_uio.mod.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | MODULE_INFO(vermagic, VERMAGIC_STRING); 6 | 7 | struct module __this_module 8 | __attribute__((section(".gnu.linkonce.this_module"))) = { 9 | .name = KBUILD_MODNAME, 10 | .init = init_module, 11 | #ifdef CONFIG_MODULE_UNLOAD 12 | .exit = cleanup_module, 13 | #endif 14 | .arch = MODULE_ARCH_INIT, 15 | }; 16 | 17 | static const struct modversion_info ____versions[] 18 | __used 19 | __attribute__((section("__versions"))) = { 20 | { 0x28950ef1, __VMLINUX_SYMBOL_STR(module_layout) }, 21 | { 0x35b6b772, __VMLINUX_SYMBOL_STR(param_ops_charp) }, 22 | { 0x15692c87, __VMLINUX_SYMBOL_STR(param_ops_int) }, 23 | { 0x2cb61da5, __VMLINUX_SYMBOL_STR(pci_unregister_driver) }, 24 | { 0x99487493, __VMLINUX_SYMBOL_STR(__pci_register_driver) }, 25 | { 0xe2d5255a, __VMLINUX_SYMBOL_STR(strcmp) }, 26 | { 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) }, 27 | { 0xd8b10333, __VMLINUX_SYMBOL_STR(uio_unregister_device) }, 28 | { 0x7cf5b2b3, __VMLINUX_SYMBOL_STR(dev_get_drvdata) }, 29 | { 0x16305289, __VMLINUX_SYMBOL_STR(warn_slowpath_null) }, 30 | { 0xf69fef42, __VMLINUX_SYMBOL_STR(sysfs_remove_group) }, 31 | { 0x584c5b17, __VMLINUX_SYMBOL_STR(dma_ops) }, 32 | { 0x78764f4e, __VMLINUX_SYMBOL_STR(pv_irq_ops) }, 33 | { 0x2ea2c95c, __VMLINUX_SYMBOL_STR(__x86_indirect_thunk_rax) }, 34 | { 0xa587ed11, __VMLINUX_SYMBOL_STR(arch_dma_alloc_attrs) }, 35 | { 0xc483a55a, __VMLINUX_SYMBOL_STR(dev_set_drvdata) }, 36 | { 0x9e00d7e6, __VMLINUX_SYMBOL_STR(__uio_register_device) }, 37 | { 0x54677dd5, __VMLINUX_SYMBOL_STR(sysfs_create_group) }, 38 | { 0x7ae5ad74, __VMLINUX_SYMBOL_STR(sme_active) }, 39 | { 0x7a7f7d68, __VMLINUX_SYMBOL_STR(dma_supported) }, 40 | { 0x59d5a7f7, __VMLINUX_SYMBOL_STR(dma_set_mask) }, 41 | { 0x37a0cba, __VMLINUX_SYMBOL_STR(kfree) }, 42 | { 0x1c3e657e, __VMLINUX_SYMBOL_STR(pci_disable_device) }, 43 | { 0xedc03953, __VMLINUX_SYMBOL_STR(iounmap) }, 44 | { 0x46734db7, __VMLINUX_SYMBOL_STR(pci_enable_device) }, 45 | { 0x41ec4c1a, __VMLINUX_SYMBOL_STR(kmem_cache_alloc_trace) }, 46 | { 0x98ab5c8d, __VMLINUX_SYMBOL_STR(kmalloc_caches) }, 47 | { 0x42c8de35, __VMLINUX_SYMBOL_STR(ioremap_nocache) }, 48 | { 0x9610eab4, __VMLINUX_SYMBOL_STR(pci_intx) }, 49 | { 0x7f59e59, __VMLINUX_SYMBOL_STR(pci_write_config_dword) }, 50 | { 0x46ecdf92, __VMLINUX_SYMBOL_STR(pci_cfg_access_unlock) }, 51 | { 0xd23a2d69, __VMLINUX_SYMBOL_STR(pci_cfg_access_lock) }, 52 | { 0xbe4a1520, __VMLINUX_SYMBOL_STR(pci_set_master) }, 53 | { 0xc140ad72, __VMLINUX_SYMBOL_STR(__dynamic_dev_dbg) }, 54 | { 0xd795224, __VMLINUX_SYMBOL_STR(dev_err) }, 55 | { 0xabda77d3, __VMLINUX_SYMBOL_STR(pci_enable_msi_range) }, 56 | { 0x8326fe63, __VMLINUX_SYMBOL_STR(dev_notice) }, 57 | { 0xac1adf42, __VMLINUX_SYMBOL_STR(pci_enable_msix) }, 58 | { 0x4cce8b07, __VMLINUX_SYMBOL_STR(_dev_info) }, 59 | { 0xd6b8e852, __VMLINUX_SYMBOL_STR(request_threaded_irq) }, 60 | { 0xf3301b35, __VMLINUX_SYMBOL_STR(pci_intx_mask_supported) }, 61 | { 0x72c53ff3, __VMLINUX_SYMBOL_STR(pci_check_and_mask_intx) }, 62 | { 0x6c4efe63, __VMLINUX_SYMBOL_STR(uio_event_notify) }, 63 | { 0x58ecf574, __VMLINUX_SYMBOL_STR(pci_disable_msix) }, 64 | { 0x79142775, __VMLINUX_SYMBOL_STR(pci_disable_msi) }, 65 | { 0xf20dabd8, __VMLINUX_SYMBOL_STR(free_irq) }, 66 | { 0x909b4067, __VMLINUX_SYMBOL_STR(pci_clear_master) }, 67 | { 0x28318305, __VMLINUX_SYMBOL_STR(snprintf) }, 68 | { 0x8f1fb6c, __VMLINUX_SYMBOL_STR(dev_num_vf) }, 69 | { 0xf0fdf6cb, __VMLINUX_SYMBOL_STR(__stack_chk_fail) }, 70 | { 0xf000f839, __VMLINUX_SYMBOL_STR(pci_enable_sriov) }, 71 | { 0xa9daec42, __VMLINUX_SYMBOL_STR(pci_disable_sriov) }, 72 | { 0x9b03fe4d, __VMLINUX_SYMBOL_STR(pci_num_vf) }, 73 | { 0x60ea2d6, __VMLINUX_SYMBOL_STR(kstrtoull) }, 74 | { 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) }, 75 | }; 76 | 77 | static const char __module_depends[] 78 | __used 79 | __attribute__((section(".modinfo"))) = 80 | "depends=uio"; 81 | 82 | 83 | MODULE_INFO(srcversion, "EAF710D62AF439C590390EE"); 84 | MODULE_INFO(rhelversion, "7.9"); 85 | #ifdef RETPOLINE 86 | MODULE_INFO(retpoline, "Y"); 87 | #endif 88 | #ifdef CONFIG_MPROFILE_KERNEL 89 | MODULE_INFO(mprofile, "Y"); 90 | #endif 91 | -------------------------------------------------------------------------------- /igb_uio/igb_uio.mod.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgpp-programer/Qcap/873ed95b9bec2d25cef0e31aa14d0bca86a745d0/igb_uio/igb_uio.mod.o -------------------------------------------------------------------------------- /igb_uio/igb_uio.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgpp-programer/Qcap/873ed95b9bec2d25cef0e31aa14d0bca86a745d0/igb_uio/igb_uio.o -------------------------------------------------------------------------------- /igb_uio/modules.order: -------------------------------------------------------------------------------- 1 | kernel//home/dpdk-kmods/linux/igb_uio/igb_uio.ko 2 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Qcap 2 | 3 | ## 1、介绍 4 | 基于dpdk实现的抓包、解码服务器 5 | 6 | #### 项目来源: 7 | 这是在我工作方向为linux C++服务端开发的时候,学习了一下dpdk,在学习dpdk的时候就顺带着写了这个服务器, 8 | 在我看来dpdk中有很多值得学习的高性能组件的实现方式,当然也是一个不错的工作方向; 9 | 于是我就想着理论和实践并行的方式写下了这个服务器,通过dpdk来抓包,实现了单包解码和会话解码的功能; 10 | #### 可以干啥: 11 | 或许你可以基于这个框架去完善解码的流程(本服务器对于解码部分写的比较简单,如果以后有合适的开源解码项目,我可能会将它移植进来), 12 | 用来做一个抓包小工具也是不错的,补充一些功能后当作个人的小项目或者毕业设计都是可以的; 13 | 14 | ## 2、架构模型 15 | 抓包线程和任务线程都可以扩展。项目抓包利用了dpdk提供的RSS机制分流,使用硬件对ip层进行分流到对应的任务队列,每个任务 16 | 队列都有一个对应的任务线程,线程独享任务队列,同时也独享流表,以此避免竞争影响性能。 17 | 但由于环境有限,该项目仅测试了单抓包线程的场景; 18 | ``` 19 | --> 数据包无锁队列1 --> 解码线程1 --> 解码 --> 输出到文件 20 | 抓包线程 -->(RSS机制ip层分流) 21 | --> 数据包无锁队列2 --> 解码线程2 --> 解码 --> 输出到文件 22 | ``` 23 | 24 | ## 3、环境安装 25 | ### 3.1、设置环境变量 26 | ``` 27 | export RTE_SDK=/home/dpdk/dpdk-stable-21.11.2 && export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig && export LD_LIBRARY_PATH=/usr/local/lib64 28 | ``` 29 | ### 3.2、安装dpdk 30 | ``` 31 | pip3 install meson ninja 32 | yum install -y numactl numactl-devel 33 | git clone https://github.com/DPDK/dpdk.git 34 | cd dpdk 35 | git fetch origin v20.11 36 | git checkout v20.11 37 | meson build 38 | cd build 39 | ninja 40 | ninja install 41 | ``` 42 | ### 3.3、检查是否安装成功: 43 | ``` 44 | pkg-config --modversion libdpdk 45 | 20.11.0 46 | ``` 47 | ### 3.4、加载驱动(2选1) 48 | #### 3.4.1、vfio 49 | ``` 50 | modprobe vfio-pci 51 | ``` 52 | #### 3.4.2、uio 53 | ``` 54 | modprobe uio 55 | git clone http://dpdk.org/git/dpdk-kmods 56 | make 57 | rmmod igb_uio.ko 58 | insmod igb_uio.ko 59 | cp igb_uio.ko /lib/modules/XXX系统内核号 60 | depmod 61 | modprobe igb_uio 62 | ``` 63 | 64 | ### 4、网卡绑定和解绑脚本 65 | ``` 66 | 目前已经把绑定网卡和解绑网卡写成了一个脚本,绑定起来更简单 67 | 注意:绑定的网卡不能是ssh连接的网卡,否则会导致ssh断开 68 | 绑定: 69 | cd Qcap/ 70 | sh bind_network_card.sh 网卡名 71 | 如: 72 | sh bind_network_card.sh ens256 73 | 74 | 解绑所有网卡: 75 | sh unbind_all_network_card.sh 76 | ``` 77 | #### 5、运行Qcap 78 | ``` 79 | cd Qcap/ 80 | mkdir build && cd build/ 81 | cmake ../ 82 | make 83 | ./Qcap 84 | ``` 85 | ### 6、运行结果 86 | ``` 87 | 系统日志:Qcap/log/system.log 88 | 输出结果:Qcap/log/packet.log 89 | ``` 90 | -------------------------------------------------------------------------------- /src/core_dpdk.cpp: -------------------------------------------------------------------------------- 1 | #include "core_dpdk.h" 2 | #include "log.h" 3 | #include "config.h" 4 | 5 | 6 | CoreDpdk::CoreDpdk() 7 | { 8 | m_name = "Qcap"; 9 | m_rxQueNumber = 1; 10 | m_txQueNumber = 0; 11 | m_isPromiscuous = Config::GetConfig()->getValue("isPromiscuous"); 12 | m_pktsRingFlags = RING_F_SP_ENQ | RING_F_MC_RTS_DEQ; 13 | m_pktRingSize = 1024; 14 | m_dpdkPortId = 0; 15 | m_running = true; 16 | m_pktRings.resize(m_rxQueNumber); 17 | } 18 | 19 | CoreDpdk::~CoreDpdk() 20 | { 21 | LOG_INFO("Qcap exit CoreDpdk"); 22 | } 23 | 24 | void CoreDpdk::UnInit() 25 | { 26 | rte_eth_dev_stop(m_dpdkPortId); 27 | rte_eal_cleanup(); 28 | } 29 | 30 | bool CoreDpdk::Init() 31 | { 32 | int ret = 0; 33 | char *env = (char *)m_name.c_str(); 34 | if ((ret = rte_eal_init(1, &env)) < 0) 35 | { 36 | LOG_ERROR("Error with eal init, return {}", ret); 37 | return false; 38 | } 39 | 40 | struct rte_mempool *mbufPool = rte_pktmbuf_pool_create("mbuf_pool", NUM_BUFS, 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 41 | if (NULL == mbufPool) 42 | { 43 | LOG_ERROR("mbuf_pool create failed"); 44 | return false; 45 | } 46 | 47 | uint16_t nb_sys_ports = rte_eth_dev_count_avail(); 48 | if (0 == nb_sys_ports) 49 | { 50 | LOG_ERROR("No Support eth found, Please bind eth"); 51 | return false; 52 | } 53 | struct rte_eth_dev_info devinfo; 54 | rte_eth_dev_info_get(m_dpdkPortId, &devinfo); 55 | int maxRxQue = devinfo.max_rx_queues; 56 | int maxTxQue = devinfo.max_tx_queues; 57 | LOG_INFO("NIC suport max rx queues = {}, mac tx queues = {}", maxRxQue, maxTxQue, ret); 58 | if(m_rxQueNumber > maxRxQue) 59 | { 60 | m_rxQueNumber = maxRxQue; 61 | } 62 | if(m_txQueNumber > maxTxQue) 63 | { 64 | m_txQueNumber = maxTxQue; 65 | } 66 | if(1 == m_rxQueNumber) 67 | { 68 | g_devConfDefault.rxmode.mq_mode = ETH_MQ_RX_NONE; 69 | g_devConfDefault.rx_adv_conf.rss_conf.rss_hf = 0; 70 | } 71 | 72 | ret = rte_eth_dev_configure(m_dpdkPortId, m_rxQueNumber, m_txQueNumber, &g_devConfDefault); 73 | if (ret < 0) 74 | { 75 | LOG_ERROR("rte_eth_dev_configure failed, return {}", ret); 76 | return false; 77 | } 78 | 79 | m_socketId = rte_eth_dev_socket_id(m_dpdkPortId); 80 | for(int i = 0; i < m_rxQueNumber; ++i) 81 | { 82 | ret = rte_eth_rx_queue_setup(m_dpdkPortId, i, 128, m_socketId, NULL, mbufPool); 83 | if (ret < 0) 84 | { 85 | LOG_ERROR("rte_eth_rx_queue_setup failed, queue id = {}, return {}}", i, ret); 86 | return false; 87 | } 88 | m_pktRings[i] = rte_ring_create("rawPktRing", rte_align32pow2(m_pktRingSize), m_socketId, m_pktsRingFlags); 89 | if(!m_pktRings[i]) 90 | { 91 | LOG_ERROR("rte_ring_create failed, queue id = {}, error {}", i, rte_errno); 92 | return false; 93 | } 94 | } 95 | 96 | ret = rte_eth_dev_start(m_dpdkPortId); 97 | if (ret < 0) 98 | { 99 | LOG_ERROR("rte_eth_dev_start failed, return {}", ret); 100 | return false; 101 | } 102 | 103 | if(m_isPromiscuous) 104 | { 105 | rte_eth_promiscuous_enable(m_dpdkPortId); 106 | } 107 | 108 | return true; 109 | } 110 | 111 | void CoreDpdk::Start() 112 | { 113 | LOG_INFO("Start PollingCapture"); 114 | PollingCapture(); 115 | UnInit(); 116 | return; 117 | } 118 | 119 | void CoreDpdk::Stop() 120 | { 121 | m_running.store(false); 122 | } 123 | 124 | void CoreDpdk::PollingCapture() 125 | { 126 | struct rte_mbuf *mbufs[BURST_SIZE]; 127 | uint16_t nbRx; 128 | int nbRxEnque; 129 | while (m_running) 130 | { 131 | usleep(50); 132 | for(int i = 0; i < m_rxQueNumber; ++i) 133 | { 134 | nbRx = rte_eth_rx_burst(m_dpdkPortId, i, mbufs, BURST_SIZE); 135 | if(0 == nbRx) 136 | { 137 | continue; 138 | } 139 | LOG_CONSOLE("rx pkt number is {}", nbRx); 140 | m_capSummary.capPktCount += nbRx; 141 | nbRxEnque = rte_ring_sp_enqueue_burst(m_pktRings[i], (void**)mbufs, nbRx, NULL); 142 | if(nbRxEnque < nbRx) 143 | { 144 | m_capSummary.dropPktCount += (nbRx - nbRxEnque); 145 | for(int i = nbRxEnque; i < nbRx; ++i) 146 | { 147 | rte_pktmbuf_free(mbufs[i]); 148 | } 149 | } 150 | } 151 | } 152 | LOG_INFO("Exit PollingCapture"); 153 | } 154 | -------------------------------------------------------------------------------- /src/core_dpdk.h: -------------------------------------------------------------------------------- 1 | #ifndef CORE_DPDK 2 | #define CORE_DPDK 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | 17 | #define HWADDR_LENGTH 6 18 | #define NUM_BUFS (4096-1) 19 | #define BURST_SIZE 128 20 | 21 | struct CapSummary 22 | { 23 | CapSummary() 24 | { 25 | dropPktCount = 0; 26 | capPktCount = 0; 27 | } 28 | uint32_t dropPktCount; 29 | uint32_t capPktCount; 30 | }; 31 | 32 | static struct rte_eth_conf g_devConfDefault = 33 | { 34 | .rxmode = { 35 | .mq_mode = ETH_MQ_RX_RSS, 36 | .max_lro_pkt_size = RTE_ETHER_MAX_LEN, 37 | .split_hdr_size = 0, 38 | .offloads = DEV_RX_OFFLOAD_CHECKSUM 39 | }, 40 | .txmode = { 41 | .mq_mode = RTE_ETH_MQ_TX_NONE, 42 | }, 43 | .rx_adv_conf = { 44 | .rss_conf = { 45 | .rss_key = NULL, 46 | .rss_hf = RTE_ETH_RSS_IP, 47 | },//RS硬件hash配置 48 | } 49 | }; 50 | 51 | class CoreDpdk 52 | { 53 | public: 54 | CoreDpdk(); 55 | ~CoreDpdk(); 56 | bool Init(); 57 | void UnInit(); 58 | void Start(); 59 | void Stop(); 60 | bool Running() { return m_running.load();} 61 | void PollingCapture(); 62 | CapSummary GetCapSummary() { return m_capSummary;} 63 | uint8_t GetRxQueNumber() {return m_rxQueNumber;} 64 | 65 | 66 | public: 67 | std::vector m_pktRings; 68 | int m_dpdkPortId; 69 | 70 | private: 71 | std::string m_name; 72 | uint8_t m_rxQueNumber; 73 | uint8_t m_txQueNumber; 74 | bool m_isPromiscuous; //是否打开混杂模式 75 | 76 | uint32_t m_pktRingSize; 77 | int32_t m_pktsRingFlags; 78 | int32_t m_socketId; 79 | 80 | std::atomic m_running; 81 | CapSummary m_capSummary; 82 | }; 83 | 84 | #endif //CORE_DPDK -------------------------------------------------------------------------------- /src/decode.h: -------------------------------------------------------------------------------- 1 | #ifndef DECODE 2 | #define DEOCDE 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "log.h" 13 | #include "help.h" 14 | #include "thread.h" 15 | #include "protocol.h" 16 | #include "flow.h" 17 | #include "flowCache.h" 18 | #include "config.h" 19 | 20 | #define BURST_SIZE 128 21 | 22 | 23 | //一层协议为一个node 24 | struct ProtoNode 25 | { 26 | ProtoNode() 27 | { 28 | m_protoType = 0xffff; 29 | m_nodeData = nullptr; 30 | } 31 | void Set(uint16_t protoType, uint8_t* nodeData) 32 | { 33 | m_protoType = protoType; 34 | m_nodeData = nodeData; 35 | } 36 | 37 | void Clear() 38 | { 39 | m_protoType = 0xffff; 40 | m_nodeData = nullptr; 41 | } 42 | 43 | uint16_t m_protoType; 44 | uint8_t* m_nodeData; 45 | }; 46 | 47 | typedef std::vector ProtoList; 48 | 49 | /* 50 | ProtoListSet 一组数据包的所有协议集合 51 | eg: 52 | | ETH | IP | TCP | HTTP |... 53 | | ETH | IPV6 | UDP | ... 54 | | ETH | IPV4 | UDP | ... 55 | */ 56 | typedef std::vector ProtoListSet; 57 | 58 | 59 | class Decode :public Thread 60 | { 61 | public: 62 | Decode(uint32_t flowOutTime, DecodeMode dm = SINGLE_PACKET); 63 | ~Decode(); 64 | void Start(int coreIndex); 65 | void Stop(); 66 | bool Running() { return m_running.load();} 67 | static void* Run(void* args); 68 | void DecodeProcess(); 69 | void SetPktRing(struct rte_ring* pktRing); 70 | 71 | private: 72 | void RecognizeProto(struct rte_mbuf** mbuf, int count, ProtoListSet& ProtoListSet); 73 | void ParseSinglePkt(ProtoListSet& ProtoListSet); 74 | void ParseFlow(ProtoListSet& ProtoListSet); 75 | void RecognizeFlow(ProtoList& protoList, FlowKey& key, FlowContext& ctx); 76 | void InsertFlowTable(FlowKey& key,FlowContext& ctx); 77 | void InsertFlow(FlowKey& key,FlowContext *ctx); 78 | void DumpFlow(const FlowKey& key, uint64_t now = 0); 79 | void DumpAllFlow(); 80 | void EraseFlow(FlowKey& key); 81 | void ClearExpiredFlow(); 82 | void ReleasePkt(struct rte_mbuf** mbuf, uint16_t count); 83 | 84 | private: 85 | DecodeMode m_decodeMode; 86 | uint32_t m_flowOutTime; 87 | std::atomic m_running; 88 | struct rte_ring* m_pktRing; 89 | FlowTable m_flowTable; 90 | FlowCache m_flowCache; 91 | }; 92 | 93 | #endif //DECODE -------------------------------------------------------------------------------- /src/flow.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOW_H 2 | #define FLOW_H 3 | 4 | #include 5 | #include "protocol.h" 6 | #include "help.h" 7 | 8 | #define OUTTIME_FLOW_TIME 60 9 | 10 | struct FlowKey 11 | { 12 | FlowKey() 13 | { 14 | m_ip1 = 0; 15 | m_ip2 = 0; 16 | m_port1 = 0; 17 | m_port2 = 0; 18 | m_proto = 0; 19 | } 20 | FlowKey(uint32_t ip1, uint32_t ip2, uint16_t port1, uint16_t port2, uint8_t proto): 21 | m_ip1(ip1), m_ip2(ip2), m_port1(port1), m_port2(port2), m_proto(proto) 22 | { 23 | if(m_ip1 < m_ip2) 24 | { 25 | uint32_t temp = m_ip1; 26 | m_ip1 = m_ip2; 27 | m_ip2 = temp; 28 | } 29 | if(m_port1 < m_port2) 30 | { 31 | uint16_t temp = m_port1; 32 | m_port1 = m_port2; 33 | m_port2 = temp; 34 | } 35 | } 36 | 37 | uint32_t GetHash() const 38 | { 39 | return m_ip1 ^ m_ip2 ^ 40 | m_port1 ^ m_port2 ^ 41 | m_proto; 42 | } 43 | 44 | uint32_t m_ip1; 45 | uint32_t m_ip2; 46 | uint16_t m_port1; 47 | uint16_t m_port2; 48 | uint16_t m_proto; 49 | }; 50 | 51 | struct FlowContext 52 | { 53 | FlowContext() : 54 | m_ip1(0), 55 | m_ip2(0), 56 | m_port1(0), 57 | m_port2(0), 58 | m_proto(0), 59 | m_curBytes(0), 60 | m_ip1To2TotalBytes(0), 61 | m_ip2To1TotalBytes(0), 62 | m_ip1To2Pkts(0), 63 | m_ip2To1Pkts(0), 64 | m_flowBeginTime(0), 65 | m_flowEndTime(0), 66 | m_isSyn(false), 67 | m_SYNCount(0), 68 | m_lastIsSYN(false), 69 | m_isFIN(false), 70 | m_FINCount(0), 71 | m_lastIsFIN(false) 72 | { 73 | } 74 | uint32_t m_ip1; 75 | uint32_t m_ip2; 76 | uint32_t m_port1; 77 | uint32_t m_port2; 78 | uint16_t m_proto; 79 | uint32_t m_curBytes; 80 | uint32_t m_ip1To2TotalBytes; 81 | uint32_t m_ip2To1TotalBytes; 82 | uint32_t m_ip1To2Pkts; 83 | uint32_t m_ip2To1Pkts; 84 | uint64_t m_flowBeginTime; 85 | uint64_t m_flowEndTime; 86 | bool m_isSyn; 87 | uint8_t m_SYNCount; 88 | bool m_lastIsSYN; 89 | bool m_isFIN; 90 | uint8_t m_FINCount; 91 | bool m_lastIsFIN; 92 | }; 93 | 94 | struct FlowKeyFunc 95 | { 96 | uint32_t operator()(const FlowKey &key) const 97 | { 98 | return key.GetHash(); 99 | } 100 | }; 101 | 102 | 103 | struct FlowKeyEqualFunc 104 | { 105 | bool operator () (const FlowKey &key1, const FlowKey &key2) const 106 | { 107 | return key1.GetHash() == key2.GetHash(); 108 | } 109 | }; 110 | 111 | typedef std::unordered_map FlowTable; 112 | #endif //FLOW_H -------------------------------------------------------------------------------- /src/flowCache.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOW_CACHE_H 2 | #define FLOW_CACHE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "flow.h" 8 | #include "assert.h" 9 | 10 | 11 | 12 | class FlowCache { 13 | public: 14 | FlowCache(int capacity = 0) : m_capacity(capacity) 15 | { 16 | m_cacheMap.clear(); 17 | m_cacheList.clear(); 18 | } 19 | 20 | void Update(const FlowKey& key, uint64_t value) 21 | { 22 | assert(m_cacheMap.find(key) != m_cacheMap.end()); 23 | auto iter = m_cacheMap.find(key); 24 | m_cacheList.erase(iter->second); 25 | m_cacheList.push_back(std::make_pair(key, value)); 26 | ListIter newIter = std::prev(m_cacheList.end()); 27 | iter->second = newIter; 28 | return ; 29 | } 30 | 31 | bool Insert(const FlowKey& key, const uint64_t value) 32 | { 33 | assert(m_cacheMap.find(key) == m_cacheMap.end()); 34 | if(0 != m_capacity && m_cacheMap.size() > m_capacity) 35 | { 36 | return false; 37 | } 38 | m_cacheList.push_back(std::make_pair(key, value)); 39 | ListIter iter = std::prev(m_cacheList.end()); 40 | m_cacheMap.insert(std::make_pair(key, iter)); 41 | return true; 42 | } 43 | 44 | bool Count(FlowKey& key) 45 | { 46 | return m_cacheMap.find(key) != m_cacheMap.end(); 47 | } 48 | 49 | bool Expired(FlowKey& key, uint64_t now) 50 | { 51 | return m_cacheMap[key]->second >= now; 52 | } 53 | 54 | bool GetExpired(FlowKey& key, uint64_t now) 55 | { 56 | if(m_cacheMap.empty()) 57 | { 58 | return false; 59 | } 60 | if(m_cacheList.front().second <= now) 61 | { 62 | key = m_cacheList.front().first; 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | void Delete(FlowKey& key) 69 | { 70 | assert(m_cacheMap.find(key) != m_cacheMap.end()); 71 | m_cacheList.erase(m_cacheMap[key]); 72 | m_cacheMap.erase(key); 73 | } 74 | 75 | private: 76 | int m_capacity; 77 | typedef std::list>::iterator ListIter; 78 | std::unordered_map m_cacheMap; 79 | std::list> m_cacheList; 80 | }; 81 | 82 | 83 | #endif //FLOW_CACHE_H -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | 4 | Logger* Logger::Instance() 5 | { 6 | static Logger* logger = new Logger; 7 | return logger; 8 | } 9 | Logger::Logger() 10 | { 11 | m_sysLogFileSize = system_log_file_size; 12 | m_sysLogFileNum = system_log_file_num; 13 | m_pktLogFileSize = pkt_log_file_size; 14 | m_pktLogFileNum = pkt_log_file_num; 15 | m_sysLogPath = log_dir_path + "system.log"; 16 | m_pktLogPath = log_dir_path + "packet.log"; 17 | m_sysLevel = "debug";//日志级别目前最低为debug 18 | m_pktLevel = "debug"; 19 | try { 20 | m_sysLogger = spdlog::create_async( 21 | "systemLog", m_sysLogPath, m_sysLogFileSize, m_sysLogFileNum); 22 | //SetLevel(m_sysLogger, m_sysLevel); 23 | m_sysLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l]: %v"); 24 | 25 | m_pktLogger = spdlog::create_async( 26 | "pktLog", m_pktLogPath, m_pktLogFileSize, m_pktLogFileNum); 27 | //SetLevel(m_pktLogger, m_pktLevel); 28 | m_pktLogger->set_pattern("%v"); 29 | } 30 | catch (const spdlog::spdlog_ex& ex) { 31 | std::cout << "[Logger] Initialization failed: " << ex.what() << std::endl; 32 | } 33 | } 34 | Logger::~Logger() 35 | { 36 | spdlog::shutdown(); 37 | } 38 | 39 | 40 | std::shared_ptr Logger::GetSysLogger() 41 | { 42 | return m_sysLogger; 43 | } 44 | std::shared_ptr Logger::GetPktLogger() 45 | { 46 | return m_pktLogger; 47 | } 48 | 49 | void Logger::SetRealTimeFlush() 50 | { 51 | if(Config::GetConfig()->getValue("realTimeFlushLog")) 52 | { 53 | spdlog::flush_every(std::chrono::seconds(1)); 54 | } 55 | return; 56 | } 57 | 58 | void Logger::SetLogLevel() 59 | { 60 | m_sysLevel = Config::GetConfig()->getValue("logLevel"); 61 | m_pktLevel = Config::GetConfig()->getValue("logLevel"); 62 | SetLevel(m_sysLogger, m_sysLevel); 63 | SetLevel(m_pktLogger, m_pktLevel); 64 | return; 65 | } 66 | 67 | void Logger::SetLevel(std::shared_ptr logger,std::string level) 68 | { 69 | if (level == "trace") { 70 | logger->set_level(spdlog::level::trace); 71 | logger->flush_on(spdlog::level::trace); 72 | } else if (level == "debug") { 73 | logger->set_level(spdlog::level::debug); 74 | logger->flush_on(spdlog::level::debug); 75 | } else if (level == "info") { 76 | logger->set_level(spdlog::level::info); 77 | logger->flush_on(spdlog::level::info); 78 | } else if (level == "warn") { 79 | logger->set_level(spdlog::level::warn); 80 | logger->flush_on(spdlog::level::warn); 81 | } else if (level == "error") { 82 | logger->set_level(spdlog::level::err); 83 | logger->flush_on(spdlog::level::err); 84 | } else if (level == "critical") { 85 | logger->set_level(spdlog::level::critical); 86 | logger->flush_on(spdlog::level::critical); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include "spdlog/spdlog.h" 5 | #include "spdlog/fmt/ostr.h" 6 | #include "spdlog/fmt/bundled/format.h" 7 | #include "spdlog/sinks/rotating_file_sink.h" 8 | #include "spdlog/sinks/stdout_color_sinks.h" 9 | #include "spdlog/async.h" 10 | #include "help.h" 11 | #include "config.h" 12 | 13 | #define LOG_TRACE(...) Logger::Instance()->GetSysLogger().get()->trace(__VA_ARGS__) 14 | #define LOG_DEBUG(...) Logger::Instance()->GetSysLogger().get()->debug(__VA_ARGS__) 15 | #define LOG_INFO(...) Logger::Instance()->GetSysLogger().get()->info(__VA_ARGS__) 16 | #define LOG_WARN(...) Logger::Instance()->GetSysLogger().get()->warn(__VA_ARGS__) 17 | #define LOG_ERROR(...) Logger::Instance()->GetSysLogger().get()->error(__VA_ARGS__) 18 | #define LOG_CRITICAL(...) Logger::Instance()->GetSysLogger().get()->critical(__VA_ARGS__) 19 | 20 | //统计数据 21 | #define LOG_STAT(...) Logger::Instance()->GetPktLogger().get()->warn(__VA_ARGS__) 22 | 23 | //控制台输出日志 24 | #define LOG_CONSOLE(...) spdlog::info(__VA_ARGS__); 25 | 26 | const uint32_t system_log_file_size = 1024 * 1024; //1M 27 | const uint32_t system_log_file_num = 1; //2个 0 1 28 | const uint32_t pkt_log_file_size = 1024 * 1024 * 10; //10M 29 | const uint32_t pkt_log_file_num = 5; //6个 30 | const std::string log_dir_path = GetQcapPath() + "/log/"; 31 | 32 | 33 | 34 | class Logger 35 | { 36 | public: 37 | static Logger* Instance(); 38 | Logger(); 39 | ~Logger(); 40 | 41 | 42 | std::shared_ptr GetSysLogger(); 43 | std::shared_ptr GetPktLogger(); 44 | void InitConfig(); 45 | void SetLogLevel(); 46 | void SetRealTimeFlush(); 47 | void SetLevel(std::shared_ptr logger,std::string level); 48 | 49 | private: 50 | std::shared_ptr m_sysLogger; 51 | std::shared_ptr m_pktLogger; 52 | uint32_t m_sysLogFileSize; 53 | uint16_t m_sysLogFileNum; 54 | uint32_t m_pktLogFileSize; 55 | uint16_t m_pktLogFileNum; 56 | std::string m_sysLogPath; 57 | std::string m_pktLogPath; 58 | std::string m_sysLevel; 59 | std::string m_pktLevel; 60 | }; 61 | 62 | 63 | #endif //LOG_H -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "core_dpdk.h" 13 | #include "decode.h" 14 | #include "log.h" 15 | #include "config.h" 16 | #include "help.h" 17 | 18 | #define BACKTRACE_SIZE 20 19 | 20 | static std::vector g_decodes; 21 | static std::vector g_coreDpdks; 22 | static std::vector core = {1, 2, 3, 4}; 23 | static int coreIndex = 0; 24 | 25 | void QcapExit() 26 | { 27 | CapSummary capSummary; 28 | bool need_dump = false; 29 | for(auto& coreDpdk : g_coreDpdks) 30 | { 31 | if(coreDpdk->Running()) 32 | { 33 | need_dump = true; 34 | coreDpdk->Stop(); 35 | capSummary.capPktCount += coreDpdk->GetCapSummary().capPktCount; 36 | capSummary.dropPktCount += coreDpdk->GetCapSummary().dropPktCount; 37 | } 38 | } 39 | LOG_INFO("cap packet number: {}, drop packet number: {}", capSummary.capPktCount, capSummary.dropPktCount); 40 | for(auto& decode : g_decodes) 41 | { 42 | if(decode->Running()) 43 | { 44 | decode->Stop(); 45 | } 46 | } 47 | return; 48 | } 49 | 50 | 51 | 52 | void SigHandle(int sig) 53 | { 54 | LOG_INFO("SIGHANDLE {}", sig); 55 | if(sig == SIGINT) 56 | { 57 | LOG_INFO("Recv Signal signal = {}, it`s ctrl + C",sig); 58 | } 59 | else if(sig == SIGSEGV || sig == SIGABRT) 60 | { 61 | void* buf[BACKTRACE_SIZE]; 62 | int n = backtrace(buf, BACKTRACE_SIZE); 63 | char** symbols = backtrace_symbols(buf, n); 64 | if(NULL == symbols) 65 | { 66 | LOG_ERROR("backtrace symbols failed"); 67 | return; 68 | } 69 | LOG_ERROR("================= Qcap crush dump info================="); 70 | for (int i = 0; i < n; i++) 71 | { 72 | std::string s = demangle(symbols[i]); 73 | LOG_ERROR("{}", s); 74 | } 75 | free(symbols); 76 | } 77 | QcapExit(); 78 | } 79 | 80 | void SignalRegister() 81 | { 82 | signal(SIGPIPE, SIG_IGN); 83 | signal(SIGINT, SigHandle); 84 | signal(SIGSEGV, SigHandle); 85 | signal(SIGABRT, SigHandle); 86 | } 87 | 88 | int main(int argc, char* argv[]) 89 | { 90 | LOG_INFO("Qcap start"); 91 | SignalRegister(); 92 | std::string tip(""); 93 | if(!Config::GetConfig()->InitConfig(tip)) 94 | { 95 | LOG_ERROR("{}", tip); 96 | return 0; 97 | } 98 | Logger::Instance()->SetLogLevel(); 99 | Logger::Instance()->SetRealTimeFlush(); 100 | std::vector tips; 101 | Config::GetConfig()->dumpConfig(tips); 102 | for(auto& t : tips) 103 | { 104 | LOG_INFO("{}", t); 105 | } 106 | 107 | CoreDpdk* cap = new CoreDpdk(); 108 | g_coreDpdks.push_back(cap); 109 | if(!cap->Init()) 110 | { 111 | LOG_ERROR("Qcap Core Dpdk Init Failed!"); 112 | return 0; 113 | } 114 | uint8_t decodeThreadNum = cap->GetRxQueNumber(); 115 | for(int i = 0; i < decodeThreadNum; ++i) 116 | { 117 | Decode* decode = nullptr; 118 | uint64_t flowOutTime = Config::GetConfig()->getValue("flowOutTime"); 119 | DecodeMode mode = (DecodeMode)Config::GetConfig()->getValue("decodeMode"); 120 | decode = new Decode(flowOutTime, mode); 121 | decode->SetPktRing(cap->m_pktRings[i]); 122 | decode->Start(core[coreIndex++]); 123 | g_decodes.push_back(decode); 124 | } 125 | cap->Start(); 126 | return 0; 127 | } -------------------------------------------------------------------------------- /src/thread.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "thread.h" 3 | #include "log.h" 4 | 5 | Thread::Thread() 6 | { 7 | m_createSuc = false; 8 | m_threadId = 0; 9 | m_threadName = "UNKNOW"; 10 | } 11 | 12 | Thread::~Thread() 13 | { 14 | 15 | } 16 | 17 | int Thread::Create(threadFunc func,void* arg, int coreIndex) 18 | { 19 | pthread_t threadId; 20 | int ret = pthread_create(&threadId, NULL, func, arg); 21 | if(ret != 0) 22 | { 23 | LOG_ERROR("pthread_create fialed! ret = {}",ret); 24 | return ret; 25 | } 26 | m_threadId = threadId; 27 | m_createSuc = true; 28 | if(coreIndex == -1) 29 | { 30 | return 0; 31 | } 32 | if(!bindThreadToCore(threadId, coreIndex)) 33 | { 34 | LOG_WARN("bind thread to core failed, therad id = {}", threadId); 35 | } 36 | return 0; 37 | } 38 | 39 | uint16_t Thread::GetThreadId() 40 | { 41 | return m_createSuc ? m_threadId : 0; 42 | } 43 | 44 | std::string Thread::GetThreadName() 45 | { 46 | return m_createSuc ? m_threadName : ""; 47 | } 48 | 49 | int Thread::SetThreadName(const std::string& threadName) 50 | { 51 | if(!m_createSuc) 52 | { 53 | LOG_ERROR("pthread_setname_np failed! thread not created"); 54 | return -1; 55 | } 56 | m_threadName = threadName; 57 | int ret = pthread_setname_np(m_threadId, m_threadName.c_str()); 58 | if(ret != 0) 59 | { 60 | LOG_ERROR("pthread_setname_np failed! ret = {}", ret); 61 | return ret; 62 | } 63 | return 1; 64 | } 65 | 66 | void Thread::Join() 67 | { 68 | if(!m_createSuc) 69 | { 70 | return ; 71 | } 72 | void *threadResult; 73 | int rt = pthread_join(m_threadId, &threadResult); 74 | if(0 != rt) 75 | { 76 | LOG_ERROR("pthread_join thread fail, return = {}, info = {}", rt, (char*)threadResult); 77 | } 78 | return; 79 | } 80 | 81 | void Thread::Detach() 82 | { 83 | if(!m_createSuc) 84 | { 85 | return ; 86 | } 87 | int rt = pthread_detach(m_threadId); 88 | if(0 != rt) 89 | { 90 | LOG_ERROR("pthread_detach thread fail, ret = {}", rt); 91 | } 92 | return; 93 | } -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | typedef void *(threadFunc) (void *); 9 | 10 | class Thread 11 | { 12 | 13 | public: 14 | Thread(); 15 | ~Thread(); 16 | int Create(threadFunc func, void* arg, int coreIndex = -1); 17 | uint16_t GetThreadId(); 18 | int SetThreadName(const std::string& threadName); 19 | std::string GetThreadName(); 20 | void Join(); 21 | void Detach(); 22 | 23 | 24 | public: 25 | bool m_createSuc; 26 | pthread_t m_threadId; 27 | std::string m_threadName; 28 | }; 29 | 30 | 31 | 32 | #endif //THREAD_H -------------------------------------------------------------------------------- /thirdpart/spdlog/async.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // 7 | // Async logging using global thread pool 8 | // All loggers created here share same global thread pool. 9 | // Each log message is pushed to a queue along with a shared pointer to the 10 | // logger. 11 | // If a logger deleted while having pending messages in the queue, it's actual 12 | // destruction will defer 13 | // until all its messages are processed by the thread pool. 14 | // This is because each message in the queue holds a shared_ptr to the 15 | // originating logger. 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace spdlog { 26 | 27 | namespace details { 28 | static const size_t default_async_q_size = 8192; 29 | } 30 | 31 | // async logger factory - creates async loggers backed with thread pool. 32 | // if a global thread pool doesn't already exist, create it with default queue 33 | // size of 8192 items and single thread. 34 | template 35 | struct async_factory_impl 36 | { 37 | template 38 | static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) 39 | { 40 | auto ®istry_inst = details::registry::instance(); 41 | 42 | // create global thread pool if not already exists.. 43 | 44 | auto &mutex = registry_inst.tp_mutex(); 45 | std::lock_guard tp_lock(mutex); 46 | auto tp = registry_inst.get_tp(); 47 | if (tp == nullptr) 48 | { 49 | tp = std::make_shared(details::default_async_q_size, 1U); 50 | registry_inst.set_tp(tp); 51 | } 52 | 53 | auto sink = std::make_shared(std::forward(args)...); 54 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); 55 | registry_inst.initialize_logger(new_logger); 56 | return new_logger; 57 | } 58 | }; 59 | 60 | using async_factory = async_factory_impl; 61 | using async_factory_nonblock = async_factory_impl; 62 | 63 | template 64 | inline std::shared_ptr create_async(std::string logger_name, SinkArgs &&... sink_args) 65 | { 66 | return async_factory::create(std::move(logger_name), std::forward(sink_args)...); 67 | } 68 | 69 | template 70 | inline std::shared_ptr create_async_nb(std::string logger_name, SinkArgs &&... sink_args) 71 | { 72 | return async_factory_nonblock::create(std::move(logger_name), std::forward(sink_args)...); 73 | } 74 | 75 | // set global thread pool. 76 | inline void init_thread_pool( 77 | size_t q_size, size_t thread_count, std::function on_thread_start, std::function on_thread_stop) 78 | { 79 | auto tp = std::make_shared(q_size, thread_count, on_thread_start, on_thread_stop); 80 | details::registry::instance().set_tp(std::move(tp)); 81 | } 82 | 83 | inline void init_thread_pool(size_t q_size, size_t thread_count, std::function on_thread_start) 84 | { 85 | init_thread_pool(q_size, thread_count, on_thread_start, [] {}); 86 | } 87 | 88 | inline void init_thread_pool(size_t q_size, size_t thread_count) 89 | { 90 | init_thread_pool( 91 | q_size, thread_count, [] {}, [] {}); 92 | } 93 | 94 | // get the global thread pool. 95 | inline std::shared_ptr thread_pool() 96 | { 97 | return details::registry::instance().get_tp(); 98 | } 99 | } // namespace spdlog 100 | -------------------------------------------------------------------------------- /thirdpart/spdlog/async_logger-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | SPDLOG_INLINE spdlog::async_logger::async_logger( 17 | std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, async_overflow_policy overflow_policy) 18 | : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) 19 | {} 20 | 21 | SPDLOG_INLINE spdlog::async_logger::async_logger( 22 | std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, async_overflow_policy overflow_policy) 23 | : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) 24 | {} 25 | 26 | // send the log message to the thread pool 27 | SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) 28 | { 29 | if (auto pool_ptr = thread_pool_.lock()) 30 | { 31 | pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); 32 | } 33 | else 34 | { 35 | throw_spdlog_ex("async log: thread pool doesn't exist anymore"); 36 | } 37 | } 38 | 39 | // send flush request to the thread pool 40 | SPDLOG_INLINE void spdlog::async_logger::flush_() 41 | { 42 | if (auto pool_ptr = thread_pool_.lock()) 43 | { 44 | pool_ptr->post_flush(shared_from_this(), overflow_policy_); 45 | } 46 | else 47 | { 48 | throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); 49 | } 50 | } 51 | 52 | // 53 | // backend functions - called from the thread pool to do the actual job 54 | // 55 | SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) 56 | { 57 | for (auto &sink : sinks_) 58 | { 59 | if (sink->should_log(msg.level)) 60 | { 61 | SPDLOG_TRY 62 | { 63 | sink->log(msg); 64 | } 65 | SPDLOG_LOGGER_CATCH(msg.source) 66 | } 67 | } 68 | 69 | if (should_flush_(msg)) 70 | { 71 | backend_flush_(); 72 | } 73 | } 74 | 75 | SPDLOG_INLINE void spdlog::async_logger::backend_flush_() 76 | { 77 | for (auto &sink : sinks_) 78 | { 79 | SPDLOG_TRY 80 | { 81 | sink->flush(); 82 | } 83 | SPDLOG_LOGGER_CATCH(source_loc()) 84 | } 85 | } 86 | 87 | SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) 88 | { 89 | auto cloned = std::make_shared(*this); 90 | cloned->name_ = std::move(new_name); 91 | return cloned; 92 | } 93 | -------------------------------------------------------------------------------- /thirdpart/spdlog/async_logger.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Fast asynchronous logger. 7 | // Uses pre allocated queue. 8 | // Creates a single back thread to pop messages from the queue and log them. 9 | // 10 | // Upon each log write the logger: 11 | // 1. Checks if its log level is enough to log the message 12 | // 2. Push a new copy of the message to a queue (or block the caller until 13 | // space is available in the queue) 14 | // Upon destruction, logs all remaining messages in the queue before 15 | // destructing.. 16 | 17 | #include 18 | 19 | namespace spdlog { 20 | 21 | // Async overflow policy - block by default. 22 | enum class async_overflow_policy 23 | { 24 | block, // Block until message can be enqueued 25 | overrun_oldest // Discard oldest message in the queue if full when trying to 26 | // add new item. 27 | }; 28 | 29 | namespace details { 30 | class thread_pool; 31 | } 32 | 33 | class SPDLOG_API async_logger final : public std::enable_shared_from_this, public logger 34 | { 35 | friend class details::thread_pool; 36 | 37 | public: 38 | template 39 | async_logger(std::string logger_name, It begin, It end, std::weak_ptr tp, 40 | async_overflow_policy overflow_policy = async_overflow_policy::block) 41 | : logger(std::move(logger_name), begin, end) 42 | , thread_pool_(std::move(tp)) 43 | , overflow_policy_(overflow_policy) 44 | {} 45 | 46 | async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr tp, 47 | async_overflow_policy overflow_policy = async_overflow_policy::block); 48 | 49 | async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr tp, 50 | async_overflow_policy overflow_policy = async_overflow_policy::block); 51 | 52 | std::shared_ptr clone(std::string new_name) override; 53 | 54 | protected: 55 | void sink_it_(const details::log_msg &msg) override; 56 | void flush_() override; 57 | void backend_sink_it_(const details::log_msg &incoming_log_msg); 58 | void backend_flush_(); 59 | 60 | private: 61 | std::weak_ptr thread_pool_; 62 | async_overflow_policy overflow_policy_; 63 | }; 64 | } // namespace spdlog 65 | 66 | #ifdef SPDLOG_HEADER_ONLY 67 | # include "async_logger-inl.h" 68 | #endif 69 | -------------------------------------------------------------------------------- /thirdpart/spdlog/cfg/argv.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | 8 | // 9 | // Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" 10 | // 11 | // set all loggers to debug level: 12 | // example.exe "SPDLOG_LEVEL=debug" 13 | 14 | // set logger1 to trace level 15 | // example.exe "SPDLOG_LEVEL=logger1=trace" 16 | 17 | // turn off all logging except for logger1 and logger2: 18 | // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" 19 | 20 | namespace spdlog { 21 | namespace cfg { 22 | 23 | // search for SPDLOG_LEVEL= in the args and use it to init the levels 24 | inline void load_argv_levels(int argc, const char **argv) 25 | { 26 | const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; 27 | for (int i = 1; i < argc; i++) 28 | { 29 | std::string arg = argv[i]; 30 | if (arg.find(spdlog_level_prefix) == 0) 31 | { 32 | auto levels_string = arg.substr(spdlog_level_prefix.size()); 33 | helpers::load_levels(levels_string); 34 | } 35 | } 36 | } 37 | 38 | inline void load_argv_levels(int argc, char **argv) 39 | { 40 | load_argv_levels(argc, const_cast(argv)); 41 | } 42 | 43 | } // namespace cfg 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /thirdpart/spdlog/cfg/env.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | 9 | // 10 | // Init levels and patterns from env variables SPDLOG_LEVEL 11 | // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). 12 | // Note - fallback to "info" level on unrecognized levels 13 | // 14 | // Examples: 15 | // 16 | // set global level to debug: 17 | // export SPDLOG_LEVEL=debug 18 | // 19 | // turn off all logging except for logger1: 20 | // export SPDLOG_LEVEL="*=off,logger1=debug" 21 | // 22 | 23 | // turn off all logging except for logger1 and logger2: 24 | // export SPDLOG_LEVEL="off,logger1=debug,logger2=info" 25 | 26 | namespace spdlog { 27 | namespace cfg { 28 | inline void load_env_levels() 29 | { 30 | auto env_val = details::os::getenv("SPDLOG_LEVEL"); 31 | if (!env_val.empty()) 32 | { 33 | helpers::load_levels(env_val); 34 | } 35 | } 36 | 37 | } // namespace cfg 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /thirdpart/spdlog/cfg/helpers-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace cfg { 21 | namespace helpers { 22 | 23 | // inplace convert to lowercase 24 | inline std::string &to_lower_(std::string &str) 25 | { 26 | std::transform( 27 | str.begin(), str.end(), str.begin(), [](char ch) { return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); 28 | return str; 29 | } 30 | 31 | // inplace trim spaces 32 | inline std::string &trim_(std::string &str) 33 | { 34 | const char *spaces = " \n\r\t"; 35 | str.erase(str.find_last_not_of(spaces) + 1); 36 | str.erase(0, str.find_first_not_of(spaces)); 37 | return str; 38 | } 39 | 40 | // return (name,value) trimmed pair from given "name=value" string. 41 | // return empty string on missing parts 42 | // "key=val" => ("key", "val") 43 | // " key = val " => ("key", "val") 44 | // "key=" => ("key", "") 45 | // "val" => ("", "val") 46 | 47 | inline std::pair extract_kv_(char sep, const std::string &str) 48 | { 49 | auto n = str.find(sep); 50 | std::string k, v; 51 | if (n == std::string::npos) 52 | { 53 | v = str; 54 | } 55 | else 56 | { 57 | k = str.substr(0, n); 58 | v = str.substr(n + 1); 59 | } 60 | return std::make_pair(trim_(k), trim_(v)); 61 | } 62 | 63 | // return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." 64 | // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} 65 | inline std::unordered_map extract_key_vals_(const std::string &str) 66 | { 67 | std::string token; 68 | std::istringstream token_stream(str); 69 | std::unordered_map rv{}; 70 | while (std::getline(token_stream, token, ',')) 71 | { 72 | if (token.empty()) 73 | { 74 | continue; 75 | } 76 | auto kv = extract_kv_('=', token); 77 | rv[kv.first] = kv.second; 78 | } 79 | return rv; 80 | } 81 | 82 | SPDLOG_INLINE void load_levels(const std::string &input) 83 | { 84 | if (input.empty() || input.size() > 512) 85 | { 86 | return; 87 | } 88 | 89 | auto key_vals = extract_key_vals_(input); 90 | std::unordered_map levels; 91 | level::level_enum global_level = level::info; 92 | bool global_level_found = false; 93 | 94 | for (auto &name_level : key_vals) 95 | { 96 | auto &logger_name = name_level.first; 97 | auto level_name = to_lower_(name_level.second); 98 | auto level = level::from_str(level_name); 99 | // ignore unrecognized level names 100 | if (level == level::off && level_name != "off") 101 | { 102 | continue; 103 | } 104 | if (logger_name.empty()) // no logger name indicate global level 105 | { 106 | global_level_found = true; 107 | global_level = level; 108 | } 109 | else 110 | { 111 | levels[logger_name] = level; 112 | } 113 | } 114 | 115 | details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr); 116 | } 117 | 118 | } // namespace helpers 119 | } // namespace cfg 120 | } // namespace spdlog 121 | -------------------------------------------------------------------------------- /thirdpart/spdlog/cfg/helpers.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace cfg { 11 | namespace helpers { 12 | // 13 | // Init levels from given string 14 | // 15 | // Examples: 16 | // 17 | // set global level to debug: "debug" 18 | // turn off all logging except for logger1: "off,logger1=debug" 19 | // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" 20 | // 21 | SPDLOG_API void load_levels(const std::string &txt); 22 | } // namespace helpers 23 | 24 | } // namespace cfg 25 | } // namespace spdlog 26 | 27 | #ifdef SPDLOG_HEADER_ONLY 28 | # include "helpers-inl.h" 29 | #endif // SPDLOG_HEADER_ONLY 30 | -------------------------------------------------------------------------------- /thirdpart/spdlog/common-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace level { 15 | 16 | #if __cplusplus >= 201703L 17 | constexpr 18 | #endif 19 | static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; 20 | 21 | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; 22 | 23 | SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 24 | { 25 | return level_string_views[l]; 26 | } 27 | 28 | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT 29 | { 30 | return short_level_names[l]; 31 | } 32 | 33 | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT 34 | { 35 | auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); 36 | if (it != std::end(level_string_views)) 37 | return static_cast(it - std::begin(level_string_views)); 38 | 39 | // check also for "warn" and "err" before giving up.. 40 | if (name == "warn") 41 | { 42 | return level::warn; 43 | } 44 | if (name == "err") 45 | { 46 | return level::err; 47 | } 48 | return level::off; 49 | } 50 | } // namespace level 51 | 52 | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) 53 | : msg_(std::move(msg)) 54 | {} 55 | 56 | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) 57 | { 58 | #ifdef SPDLOG_USE_STD_FORMAT 59 | msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); 60 | #else 61 | memory_buf_t outbuf; 62 | fmt::format_system_error(outbuf, last_errno, msg.c_str()); 63 | msg_ = fmt::to_string(outbuf); 64 | #endif 65 | } 66 | 67 | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT 68 | { 69 | return msg_.c_str(); 70 | } 71 | 72 | SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) 73 | { 74 | SPDLOG_THROW(spdlog_ex(msg, last_errno)); 75 | } 76 | 77 | SPDLOG_INLINE void throw_spdlog_ex(std::string msg) 78 | { 79 | SPDLOG_THROW(spdlog_ex(std::move(msg))); 80 | } 81 | 82 | } // namespace spdlog 83 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/backtracer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | namespace spdlog { 10 | namespace details { 11 | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) 12 | { 13 | std::lock_guard lock(other.mutex_); 14 | enabled_ = other.enabled(); 15 | messages_ = other.messages_; 16 | } 17 | 18 | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT 19 | { 20 | std::lock_guard lock(other.mutex_); 21 | enabled_ = other.enabled(); 22 | messages_ = std::move(other.messages_); 23 | } 24 | 25 | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) 26 | { 27 | std::lock_guard lock(mutex_); 28 | enabled_ = other.enabled(); 29 | messages_ = std::move(other.messages_); 30 | return *this; 31 | } 32 | 33 | SPDLOG_INLINE void backtracer::enable(size_t size) 34 | { 35 | std::lock_guard lock{mutex_}; 36 | enabled_.store(true, std::memory_order_relaxed); 37 | messages_ = circular_q{size}; 38 | } 39 | 40 | SPDLOG_INLINE void backtracer::disable() 41 | { 42 | std::lock_guard lock{mutex_}; 43 | enabled_.store(false, std::memory_order_relaxed); 44 | } 45 | 46 | SPDLOG_INLINE bool backtracer::enabled() const 47 | { 48 | return enabled_.load(std::memory_order_relaxed); 49 | } 50 | 51 | SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) 52 | { 53 | std::lock_guard lock{mutex_}; 54 | messages_.push_back(log_msg_buffer{msg}); 55 | } 56 | 57 | // pop all items in the q and apply the given fun on each of them. 58 | SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) 59 | { 60 | std::lock_guard lock{mutex_}; 61 | while (!messages_.empty()) 62 | { 63 | auto &front_msg = messages_.front(); 64 | fun(front_msg); 65 | messages_.pop_front(); 66 | } 67 | } 68 | } // namespace details 69 | } // namespace spdlog 70 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/backtracer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // Store log messages in circular buffer. 14 | // Useful for storing debug data in case of error/warning happens. 15 | 16 | namespace spdlog { 17 | namespace details { 18 | class SPDLOG_API backtracer 19 | { 20 | mutable std::mutex mutex_; 21 | std::atomic enabled_{false}; 22 | circular_q messages_; 23 | 24 | public: 25 | backtracer() = default; 26 | backtracer(const backtracer &other); 27 | 28 | backtracer(backtracer &&other) SPDLOG_NOEXCEPT; 29 | backtracer &operator=(backtracer other); 30 | 31 | void enable(size_t size); 32 | void disable(); 33 | bool enabled() const; 34 | void push_back(const log_msg &msg); 35 | 36 | // pop all items in the q and apply the given fun on each of them. 37 | void foreach_pop(std::function fun); 38 | }; 39 | 40 | } // namespace details 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | # include "backtracer-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/circular_q.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | // circular q view of std::vector. 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace spdlog { 11 | namespace details { 12 | template 13 | class circular_q 14 | { 15 | size_t max_items_ = 0; 16 | typename std::vector::size_type head_ = 0; 17 | typename std::vector::size_type tail_ = 0; 18 | size_t overrun_counter_ = 0; 19 | std::vector v_; 20 | 21 | public: 22 | using value_type = T; 23 | 24 | // empty ctor - create a disabled queue with no elements allocated at all 25 | circular_q() = default; 26 | 27 | explicit circular_q(size_t max_items) 28 | : max_items_(max_items + 1) // one item is reserved as marker for full q 29 | , v_(max_items_) 30 | {} 31 | 32 | circular_q(const circular_q &) = default; 33 | circular_q &operator=(const circular_q &) = default; 34 | 35 | // move cannot be default, 36 | // since we need to reset head_, tail_, etc to zero in the moved object 37 | circular_q(circular_q &&other) SPDLOG_NOEXCEPT 38 | { 39 | copy_moveable(std::move(other)); 40 | } 41 | 42 | circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT 43 | { 44 | copy_moveable(std::move(other)); 45 | return *this; 46 | } 47 | 48 | // push back, overrun (oldest) item if no room left 49 | void push_back(T &&item) 50 | { 51 | if (max_items_ > 0) 52 | { 53 | v_[tail_] = std::move(item); 54 | tail_ = (tail_ + 1) % max_items_; 55 | 56 | if (tail_ == head_) // overrun last item if full 57 | { 58 | head_ = (head_ + 1) % max_items_; 59 | ++overrun_counter_; 60 | } 61 | } 62 | } 63 | 64 | // Return reference to the front item. 65 | // If there are no elements in the container, the behavior is undefined. 66 | const T &front() const 67 | { 68 | return v_[head_]; 69 | } 70 | 71 | T &front() 72 | { 73 | return v_[head_]; 74 | } 75 | 76 | // Return number of elements actually stored 77 | size_t size() const 78 | { 79 | if (tail_ >= head_) 80 | { 81 | return tail_ - head_; 82 | } 83 | else 84 | { 85 | return max_items_ - (head_ - tail_); 86 | } 87 | } 88 | 89 | // Return const reference to item by index. 90 | // If index is out of range 0…size()-1, the behavior is undefined. 91 | const T &at(size_t i) const 92 | { 93 | assert(i < size()); 94 | return v_[(head_ + i) % max_items_]; 95 | } 96 | 97 | // Pop item from front. 98 | // If there are no elements in the container, the behavior is undefined. 99 | void pop_front() 100 | { 101 | head_ = (head_ + 1) % max_items_; 102 | } 103 | 104 | bool empty() const 105 | { 106 | return tail_ == head_; 107 | } 108 | 109 | bool full() const 110 | { 111 | // head is ahead of the tail by 1 112 | if (max_items_ > 0) 113 | { 114 | return ((tail_ + 1) % max_items_) == head_; 115 | } 116 | return false; 117 | } 118 | 119 | size_t overrun_counter() const 120 | { 121 | return overrun_counter_; 122 | } 123 | 124 | void reset_overrun_counter() 125 | { 126 | overrun_counter_ = 0; 127 | } 128 | 129 | private: 130 | // copy from other&& and reset it to disabled state 131 | void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT 132 | { 133 | max_items_ = other.max_items_; 134 | head_ = other.head_; 135 | tail_ = other.tail_; 136 | overrun_counter_ = other.overrun_counter_; 137 | v_ = std::move(other.v_); 138 | 139 | // put &&other in disabled, but valid state 140 | other.max_items_ = 0; 141 | other.head_ = other.tail_ = 0; 142 | other.overrun_counter_ = 0; 143 | } 144 | }; 145 | } // namespace details 146 | } // namespace spdlog 147 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/console_globals.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | struct console_mutex 13 | { 14 | using mutex_t = std::mutex; 15 | static mutex_t &mutex() 16 | { 17 | static mutex_t s_mutex; 18 | return s_mutex; 19 | } 20 | }; 21 | 22 | struct console_nullmutex 23 | { 24 | using mutex_t = null_mutex; 25 | static mutex_t &mutex() 26 | { 27 | static mutex_t s_mutex; 28 | return s_mutex; 29 | } 30 | }; 31 | } // namespace details 32 | } // namespace spdlog 33 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/file_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | 12 | // Helper class for file sinks. 13 | // When failing to open a file, retry several times(5) with a delay interval(10 ms). 14 | // Throw spdlog_ex exception on errors. 15 | 16 | class SPDLOG_API file_helper 17 | { 18 | public: 19 | file_helper() = default; 20 | explicit file_helper(const file_event_handlers &event_handlers); 21 | 22 | file_helper(const file_helper &) = delete; 23 | file_helper &operator=(const file_helper &) = delete; 24 | ~file_helper(); 25 | 26 | void open(const filename_t &fname, bool truncate = false); 27 | void reopen(bool truncate); 28 | void flush(); 29 | void close(); 30 | void write(const memory_buf_t &buf); 31 | size_t size() const; 32 | const filename_t &filename() const; 33 | 34 | // 35 | // return file path and its extension: 36 | // 37 | // "mylog.txt" => ("mylog", ".txt") 38 | // "mylog" => ("mylog", "") 39 | // "mylog." => ("mylog.", "") 40 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") 41 | // 42 | // the starting dot in filenames is ignored (hidden files): 43 | // 44 | // ".mylog" => (".mylog". "") 45 | // "my_folder/.mylog" => ("my_folder/.mylog", "") 46 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") 47 | static std::tuple split_by_extension(const filename_t &fname); 48 | 49 | private: 50 | const int open_tries_ = 5; 51 | const unsigned int open_interval_ = 10; 52 | std::FILE *fd_{nullptr}; 53 | filename_t filename_; 54 | file_event_handlers event_handlers_; 55 | }; 56 | } // namespace details 57 | } // namespace spdlog 58 | 59 | #ifdef SPDLOG_HEADER_ONLY 60 | # include "file_helper-inl.h" 61 | #endif 62 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/log_msg-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace details { 14 | 15 | SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, 16 | spdlog::level::level_enum lvl, spdlog::string_view_t msg) 17 | : logger_name(a_logger_name) 18 | , level(lvl) 19 | , time(log_time) 20 | #ifndef SPDLOG_NO_THREAD_ID 21 | , thread_id(os::thread_id()) 22 | #endif 23 | , source(loc) 24 | , payload(msg) 25 | {} 26 | 27 | SPDLOG_INLINE log_msg::log_msg( 28 | spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 29 | : log_msg(os::now(), loc, a_logger_name, lvl, msg) 30 | {} 31 | 32 | SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) 33 | : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) 34 | {} 35 | 36 | } // namespace details 37 | } // namespace spdlog 38 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/log_msg.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | namespace details { 11 | struct SPDLOG_API log_msg 12 | { 13 | log_msg() = default; 14 | log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 15 | log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); 16 | log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); 17 | log_msg(const log_msg &other) = default; 18 | log_msg &operator=(const log_msg &other) = default; 19 | 20 | string_view_t logger_name; 21 | level::level_enum level{level::off}; 22 | log_clock::time_point time; 23 | size_t thread_id{0}; 24 | 25 | // wrapping the formatted text with color (updated by pattern_formatter). 26 | mutable size_t color_range_start{0}; 27 | mutable size_t color_range_end{0}; 28 | 29 | source_loc source; 30 | string_view_t payload; 31 | }; 32 | } // namespace details 33 | } // namespace spdlog 34 | 35 | #ifdef SPDLOG_HEADER_ONLY 36 | # include "log_msg-inl.h" 37 | #endif 38 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/log_msg_buffer-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) 14 | : log_msg{orig_msg} 15 | { 16 | buffer.append(logger_name.begin(), logger_name.end()); 17 | buffer.append(payload.begin(), payload.end()); 18 | update_string_views(); 19 | } 20 | 21 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) 22 | : log_msg{other} 23 | { 24 | buffer.append(logger_name.begin(), logger_name.end()); 25 | buffer.append(payload.begin(), payload.end()); 26 | update_string_views(); 27 | } 28 | 29 | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)} 30 | { 31 | update_string_views(); 32 | } 33 | 34 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) 35 | { 36 | log_msg::operator=(other); 37 | buffer.clear(); 38 | buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); 39 | update_string_views(); 40 | return *this; 41 | } 42 | 43 | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT 44 | { 45 | log_msg::operator=(other); 46 | buffer = std::move(other.buffer); 47 | update_string_views(); 48 | return *this; 49 | } 50 | 51 | SPDLOG_INLINE void log_msg_buffer::update_string_views() 52 | { 53 | logger_name = string_view_t{buffer.data(), logger_name.size()}; 54 | payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; 55 | } 56 | 57 | } // namespace details 58 | } // namespace spdlog 59 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/log_msg_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace spdlog { 9 | namespace details { 10 | 11 | // Extend log_msg with internal buffer to store its payload. 12 | // This is needed since log_msg holds string_views that points to stack data. 13 | 14 | class SPDLOG_API log_msg_buffer : public log_msg 15 | { 16 | memory_buf_t buffer; 17 | void update_string_views(); 18 | 19 | public: 20 | log_msg_buffer() = default; 21 | explicit log_msg_buffer(const log_msg &orig_msg); 22 | log_msg_buffer(const log_msg_buffer &other); 23 | log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 24 | log_msg_buffer &operator=(const log_msg_buffer &other); 25 | log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; 26 | }; 27 | 28 | } // namespace details 29 | } // namespace spdlog 30 | 31 | #ifdef SPDLOG_HEADER_ONLY 32 | # include "log_msg_buffer-inl.h" 33 | #endif 34 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/mpmc_blocking_q.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // multi producer-multi consumer blocking queue. 7 | // enqueue(..) - will block until room found to put the new message. 8 | // enqueue_nowait(..) - will return immediately with false if no room left in 9 | // the queue. 10 | // dequeue_for(..) - will block until the queue is not empty or timeout have 11 | // passed. 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace spdlog { 19 | namespace details { 20 | 21 | template 22 | class mpmc_blocking_queue 23 | { 24 | public: 25 | using item_type = T; 26 | explicit mpmc_blocking_queue(size_t max_items) 27 | : q_(max_items) 28 | {} 29 | 30 | #ifndef __MINGW32__ 31 | // try to enqueue and block if no room left 32 | void enqueue(T &&item) 33 | { 34 | { 35 | std::unique_lock lock(queue_mutex_); 36 | pop_cv_.wait(lock, [this] { return !this->q_.full(); }); 37 | q_.push_back(std::move(item)); 38 | } 39 | push_cv_.notify_one(); 40 | } 41 | 42 | // enqueue immediately. overrun oldest message in the queue if no room left. 43 | void enqueue_nowait(T &&item) 44 | { 45 | { 46 | std::unique_lock lock(queue_mutex_); 47 | q_.push_back(std::move(item)); 48 | } 49 | push_cv_.notify_one(); 50 | } 51 | 52 | // try to dequeue item. if no item found. wait up to timeout and try again 53 | // Return true, if succeeded dequeue item, false otherwise 54 | bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) 55 | { 56 | { 57 | std::unique_lock lock(queue_mutex_); 58 | if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) 59 | { 60 | return false; 61 | } 62 | popped_item = std::move(q_.front()); 63 | q_.pop_front(); 64 | } 65 | pop_cv_.notify_one(); 66 | return true; 67 | } 68 | 69 | #else 70 | // apparently mingw deadlocks if the mutex is released before cv.notify_one(), 71 | // so release the mutex at the very end each function. 72 | 73 | // try to enqueue and block if no room left 74 | void enqueue(T &&item) 75 | { 76 | std::unique_lock lock(queue_mutex_); 77 | pop_cv_.wait(lock, [this] { return !this->q_.full(); }); 78 | q_.push_back(std::move(item)); 79 | push_cv_.notify_one(); 80 | } 81 | 82 | // enqueue immediately. overrun oldest message in the queue if no room left. 83 | void enqueue_nowait(T &&item) 84 | { 85 | std::unique_lock lock(queue_mutex_); 86 | q_.push_back(std::move(item)); 87 | push_cv_.notify_one(); 88 | } 89 | 90 | // try to dequeue item. if no item found. wait up to timeout and try again 91 | // Return true, if succeeded dequeue item, false otherwise 92 | bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) 93 | { 94 | std::unique_lock lock(queue_mutex_); 95 | if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) 96 | { 97 | return false; 98 | } 99 | popped_item = std::move(q_.front()); 100 | q_.pop_front(); 101 | pop_cv_.notify_one(); 102 | return true; 103 | } 104 | 105 | #endif 106 | 107 | size_t overrun_counter() 108 | { 109 | std::unique_lock lock(queue_mutex_); 110 | return q_.overrun_counter(); 111 | } 112 | 113 | size_t size() 114 | { 115 | std::unique_lock lock(queue_mutex_); 116 | return q_.size(); 117 | } 118 | 119 | void reset_overrun_counter() 120 | { 121 | std::unique_lock lock(queue_mutex_); 122 | q_.reset_overrun_counter(); 123 | } 124 | 125 | private: 126 | std::mutex queue_mutex_; 127 | std::condition_variable push_cv_; 128 | std::condition_variable pop_cv_; 129 | spdlog::details::circular_q q_; 130 | }; 131 | } // namespace details 132 | } // namespace spdlog 133 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/null_mutex.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | // null, no cost dummy "mutex" and dummy "atomic" int 9 | 10 | namespace spdlog { 11 | namespace details { 12 | struct null_mutex 13 | { 14 | void lock() const {} 15 | void unlock() const {} 16 | }; 17 | 18 | struct null_atomic_int 19 | { 20 | int value; 21 | null_atomic_int() = default; 22 | 23 | explicit null_atomic_int(int new_value) 24 | : value(new_value) 25 | {} 26 | 27 | int load(std::memory_order = std::memory_order_relaxed) const 28 | { 29 | return value; 30 | } 31 | 32 | void store(int new_value, std::memory_order = std::memory_order_relaxed) 33 | { 34 | value = new_value; 35 | } 36 | 37 | int exchange(int new_value, std::memory_order = std::memory_order_relaxed) 38 | { 39 | std::swap(new_value, value); 40 | return new_value; // return value before the call 41 | } 42 | }; 43 | 44 | } // namespace details 45 | } // namespace spdlog 46 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/os.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include // std::time_t 8 | 9 | namespace spdlog { 10 | namespace details { 11 | namespace os { 12 | 13 | SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; 14 | 15 | SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; 16 | 17 | SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; 18 | 19 | SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; 20 | 21 | SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; 22 | 23 | // eol definition 24 | #if !defined(SPDLOG_EOL) 25 | # ifdef _WIN32 26 | # define SPDLOG_EOL "\r\n" 27 | # else 28 | # define SPDLOG_EOL "\n" 29 | # endif 30 | #endif 31 | 32 | SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; 33 | 34 | // folder separator 35 | #if !defined(SPDLOG_FOLDER_SEPS) 36 | # ifdef _WIN32 37 | # define SPDLOG_FOLDER_SEPS "\\/" 38 | # else 39 | # define SPDLOG_FOLDER_SEPS "/" 40 | # endif 41 | #endif 42 | 43 | SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS; 44 | SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS); 45 | 46 | // fopen_s on non windows for writing 47 | SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); 48 | 49 | // Remove filename. return 0 on success 50 | SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; 51 | 52 | // Remove file if exists. return 0 on success 53 | // Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) 54 | SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; 55 | 56 | SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; 57 | 58 | // Return if file exists. 59 | SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; 60 | 61 | // Return file size according to open FILE* object 62 | SPDLOG_API size_t filesize(FILE *f); 63 | 64 | // Return utc offset in minutes or throw spdlog_ex on failure 65 | SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); 66 | 67 | // Return current thread id as size_t 68 | // It exists because the std::this_thread::get_id() is much slower(especially 69 | // under VS 2013) 70 | SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; 71 | 72 | // Return current thread id as size_t (from thread local storage) 73 | SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; 74 | 75 | // This is avoid msvc issue in sleep_for that happens if the clock changes. 76 | // See https://github.com/gabime/spdlog/issues/609 77 | SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT; 78 | 79 | SPDLOG_API std::string filename_to_str(const filename_t &filename); 80 | 81 | SPDLOG_API int pid() SPDLOG_NOEXCEPT; 82 | 83 | // Determine if the terminal supports colors 84 | // Source: https://github.com/agauniyal/rang/ 85 | SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; 86 | 87 | // Determine if the terminal attached 88 | // Source: https://github.com/agauniyal/rang/ 89 | SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; 90 | 91 | #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) 92 | SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); 93 | 94 | SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); 95 | #endif 96 | 97 | // Return directory name from given path or empty string 98 | // "abc/file" => "abc" 99 | // "abc/" => "abc" 100 | // "abc" => "" 101 | // "abc///" => "abc//" 102 | SPDLOG_API filename_t dir_name(const filename_t &path); 103 | 104 | // Create a dir from the given path. 105 | // Return true if succeeded or if this dir already exists. 106 | SPDLOG_API bool create_dir(const filename_t &path); 107 | 108 | // non thread safe, cross platform getenv/getenv_s 109 | // return empty string if field not found 110 | SPDLOG_API std::string getenv(const char *field); 111 | 112 | } // namespace os 113 | } // namespace details 114 | } // namespace spdlog 115 | 116 | #ifdef SPDLOG_HEADER_ONLY 117 | # include "os-inl.h" 118 | #endif 119 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/periodic_worker-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | namespace spdlog { 11 | namespace details { 12 | 13 | // stop the worker thread and join it 14 | SPDLOG_INLINE periodic_worker::~periodic_worker() 15 | { 16 | if (worker_thread_.joinable()) 17 | { 18 | { 19 | std::lock_guard lock(mutex_); 20 | active_ = false; 21 | } 22 | cv_.notify_one(); 23 | worker_thread_.join(); 24 | } 25 | } 26 | 27 | } // namespace details 28 | } // namespace spdlog 29 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/periodic_worker.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // periodic worker thread - periodically executes the given callback function. 7 | // 8 | // RAII over the owned thread: 9 | // creates the thread on construction. 10 | // stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | namespace spdlog { 18 | namespace details { 19 | 20 | class SPDLOG_API periodic_worker 21 | { 22 | public: 23 | template 24 | periodic_worker(const std::function &callback_fun, std::chrono::duration interval) { 25 | active_ = (interval > std::chrono::duration::zero()); 26 | if (!active_) 27 | { 28 | return; 29 | } 30 | 31 | worker_thread_ = std::thread([this, callback_fun, interval]() { 32 | for (;;) 33 | { 34 | std::unique_lock lock(this->mutex_); 35 | if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) 36 | { 37 | return; // active_ == false, so exit this thread 38 | } 39 | callback_fun(); 40 | } 41 | }); 42 | } 43 | periodic_worker(const periodic_worker &) = delete; 44 | periodic_worker &operator=(const periodic_worker &) = delete; 45 | // stop the worker thread and join it 46 | ~periodic_worker(); 47 | 48 | private: 49 | bool active_; 50 | std::thread worker_thread_; 51 | std::mutex mutex_; 52 | std::condition_variable cv_; 53 | }; 54 | } // namespace details 55 | } // namespace spdlog 56 | 57 | #ifdef SPDLOG_HEADER_ONLY 58 | # include "periodic_worker-inl.h" 59 | #endif 60 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/registry.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Loggers registry of unique name->logger pointer 7 | // An attempt to create a logger with an already existing name will result with spdlog_ex exception. 8 | // If user requests a non existing logger, nullptr will be returned 9 | // This class is thread safe 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace spdlog { 22 | class logger; 23 | 24 | namespace details { 25 | class thread_pool; 26 | 27 | class SPDLOG_API registry 28 | { 29 | public: 30 | using log_levels = std::unordered_map; 31 | registry(const registry &) = delete; 32 | registry &operator=(const registry &) = delete; 33 | 34 | void register_logger(std::shared_ptr new_logger); 35 | void initialize_logger(std::shared_ptr new_logger); 36 | std::shared_ptr get(const std::string &logger_name); 37 | std::shared_ptr default_logger(); 38 | 39 | // Return raw ptr to the default logger. 40 | // To be used directly by the spdlog default api (e.g. spdlog::info) 41 | // This make the default API faster, but cannot be used concurrently with set_default_logger(). 42 | // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. 43 | logger *get_default_raw(); 44 | 45 | // set default logger. 46 | // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. 47 | void set_default_logger(std::shared_ptr new_default_logger); 48 | 49 | void set_tp(std::shared_ptr tp); 50 | 51 | std::shared_ptr get_tp(); 52 | 53 | // Set global formatter. Each sink in each logger will get a clone of this object 54 | void set_formatter(std::unique_ptr formatter); 55 | 56 | void enable_backtrace(size_t n_messages); 57 | 58 | void disable_backtrace(); 59 | 60 | void set_level(level::level_enum log_level); 61 | 62 | void flush_on(level::level_enum log_level); 63 | 64 | template 65 | void flush_every(std::chrono::duration interval) 66 | { 67 | std::lock_guard lock(flusher_mutex_); 68 | auto clbk = [this]() { this->flush_all(); }; 69 | periodic_flusher_ = details::make_unique(clbk, interval); 70 | } 71 | 72 | void set_error_handler(err_handler handler); 73 | 74 | void apply_all(const std::function)> &fun); 75 | 76 | void flush_all(); 77 | 78 | void drop(const std::string &logger_name); 79 | 80 | void drop_all(); 81 | 82 | // clean all resources and threads started by the registry 83 | void shutdown(); 84 | 85 | std::recursive_mutex &tp_mutex(); 86 | 87 | void set_automatic_registration(bool automatic_registration); 88 | 89 | // set levels for all existing/future loggers. global_level can be null if should not set. 90 | void set_levels(log_levels levels, level::level_enum *global_level); 91 | 92 | static registry &instance(); 93 | 94 | private: 95 | registry(); 96 | ~registry(); 97 | 98 | void throw_if_exists_(const std::string &logger_name); 99 | void register_logger_(std::shared_ptr new_logger); 100 | bool set_level_from_cfg_(logger *logger); 101 | std::mutex logger_map_mutex_, flusher_mutex_; 102 | std::recursive_mutex tp_mutex_; 103 | std::unordered_map> loggers_; 104 | log_levels log_levels_; 105 | std::unique_ptr formatter_; 106 | spdlog::level::level_enum global_log_level_ = level::info; 107 | level::level_enum flush_level_ = level::off; 108 | err_handler err_handler_; 109 | std::shared_ptr tp_; 110 | std::unique_ptr periodic_flusher_; 111 | std::shared_ptr default_logger_; 112 | bool automatic_registration_ = true; 113 | size_t backtrace_n_messages_ = 0; 114 | }; 115 | 116 | } // namespace details 117 | } // namespace spdlog 118 | 119 | #ifdef SPDLOG_HEADER_ONLY 120 | # include "registry-inl.h" 121 | #endif 122 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/synchronous_factory.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "registry.h" 7 | 8 | namespace spdlog { 9 | 10 | // Default logger factory- creates synchronous loggers 11 | class logger; 12 | 13 | struct synchronous_factory 14 | { 15 | template 16 | static std::shared_ptr create(std::string logger_name, SinkArgs &&... args) 17 | { 18 | auto sink = std::make_shared(std::forward(args)...); 19 | auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); 20 | details::registry::instance().initialize_logger(new_logger); 21 | return new_logger; 22 | } 23 | }; 24 | } // namespace spdlog 25 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/tcp_client-windows.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define WIN32_LEAN_AND_MEAN 7 | // tcp client helper 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #pragma comment(lib, "Ws2_32.lib") 19 | #pragma comment(lib, "Mswsock.lib") 20 | #pragma comment(lib, "AdvApi32.lib") 21 | 22 | namespace spdlog { 23 | namespace details { 24 | class tcp_client 25 | { 26 | SOCKET socket_ = INVALID_SOCKET; 27 | 28 | static void init_winsock_() 29 | { 30 | WSADATA wsaData; 31 | auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); 32 | if (rv != 0) 33 | { 34 | throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); 35 | } 36 | } 37 | 38 | static void throw_winsock_error_(const std::string &msg, int last_error) 39 | { 40 | char buf[512]; 41 | ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, 42 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); 43 | 44 | throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); 45 | } 46 | 47 | public: 48 | tcp_client() 49 | { 50 | init_winsock_(); 51 | } 52 | 53 | ~tcp_client() 54 | { 55 | close(); 56 | ::WSACleanup(); 57 | } 58 | 59 | bool is_connected() const 60 | { 61 | return socket_ != INVALID_SOCKET; 62 | } 63 | 64 | void close() 65 | { 66 | ::closesocket(socket_); 67 | socket_ = INVALID_SOCKET; 68 | } 69 | 70 | SOCKET fd() const 71 | { 72 | return socket_; 73 | } 74 | 75 | // try to connect or throw on failure 76 | void connect(const std::string &host, int port) 77 | { 78 | if (is_connected()) 79 | { 80 | close(); 81 | } 82 | struct addrinfo hints 83 | {}; 84 | ZeroMemory(&hints, sizeof(hints)); 85 | 86 | hints.ai_family = AF_INET; // IPv4 87 | hints.ai_socktype = SOCK_STREAM; // TCP 88 | hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value 89 | hints.ai_protocol = 0; 90 | 91 | auto port_str = std::to_string(port); 92 | struct addrinfo *addrinfo_result; 93 | auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); 94 | int last_error = 0; 95 | if (rv != 0) 96 | { 97 | last_error = ::WSAGetLastError(); 98 | WSACleanup(); 99 | throw_winsock_error_("getaddrinfo failed", last_error); 100 | } 101 | 102 | // Try each address until we successfully connect(2). 103 | 104 | for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) 105 | { 106 | socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 107 | if (socket_ == INVALID_SOCKET) 108 | { 109 | last_error = ::WSAGetLastError(); 110 | WSACleanup(); 111 | continue; 112 | } 113 | if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) 114 | { 115 | break; 116 | } 117 | else 118 | { 119 | last_error = ::WSAGetLastError(); 120 | close(); 121 | } 122 | } 123 | ::freeaddrinfo(addrinfo_result); 124 | if (socket_ == INVALID_SOCKET) 125 | { 126 | WSACleanup(); 127 | throw_winsock_error_("connect failed", last_error); 128 | } 129 | 130 | // set TCP_NODELAY 131 | int enable_flag = 1; 132 | ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); 133 | } 134 | 135 | // Send exactly n_bytes of the given data. 136 | // On error close the connection and throw. 137 | void send(const char *data, size_t n_bytes) 138 | { 139 | size_t bytes_sent = 0; 140 | while (bytes_sent < n_bytes) 141 | { 142 | const int send_flags = 0; 143 | auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); 144 | if (write_result == SOCKET_ERROR) 145 | { 146 | int last_error = ::WSAGetLastError(); 147 | close(); 148 | throw_winsock_error_("send failed", last_error); 149 | } 150 | 151 | if (write_result == 0) // (probably should not happen but in any case..) 152 | { 153 | break; 154 | } 155 | bytes_sent += static_cast(write_result); 156 | } 157 | } 158 | }; 159 | } // namespace details 160 | } // namespace spdlog 161 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/tcp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | # error include tcp_client-windows.h instead 8 | #endif 9 | 10 | // tcp client helper 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | namespace spdlog { 23 | namespace details { 24 | class tcp_client 25 | { 26 | int socket_ = -1; 27 | 28 | public: 29 | bool is_connected() const 30 | { 31 | return socket_ != -1; 32 | } 33 | 34 | void close() 35 | { 36 | if (is_connected()) 37 | { 38 | ::close(socket_); 39 | socket_ = -1; 40 | } 41 | } 42 | 43 | int fd() const 44 | { 45 | return socket_; 46 | } 47 | 48 | ~tcp_client() 49 | { 50 | close(); 51 | } 52 | 53 | // try to connect or throw on failure 54 | void connect(const std::string &host, int port) 55 | { 56 | close(); 57 | struct addrinfo hints 58 | {}; 59 | memset(&hints, 0, sizeof(struct addrinfo)); 60 | hints.ai_family = AF_INET; // IPv4 61 | hints.ai_socktype = SOCK_STREAM; // TCP 62 | hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value 63 | hints.ai_protocol = 0; 64 | 65 | auto port_str = std::to_string(port); 66 | struct addrinfo *addrinfo_result; 67 | auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); 68 | if (rv != 0) 69 | { 70 | throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); 71 | } 72 | 73 | // Try each address until we successfully connect(2). 74 | int last_errno = 0; 75 | for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) 76 | { 77 | #if defined(SOCK_CLOEXEC) 78 | const int flags = SOCK_CLOEXEC; 79 | #else 80 | const int flags = 0; 81 | #endif 82 | socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); 83 | if (socket_ == -1) 84 | { 85 | last_errno = errno; 86 | continue; 87 | } 88 | rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); 89 | if (rv == 0) 90 | { 91 | break; 92 | } 93 | last_errno = errno; 94 | ::close(socket_); 95 | socket_ = -1; 96 | } 97 | ::freeaddrinfo(addrinfo_result); 98 | if (socket_ == -1) 99 | { 100 | throw_spdlog_ex("::connect failed", last_errno); 101 | } 102 | 103 | // set TCP_NODELAY 104 | int enable_flag = 1; 105 | ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), sizeof(enable_flag)); 106 | 107 | // prevent sigpipe on systems where MSG_NOSIGNAL is not available 108 | #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 109 | ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&enable_flag), sizeof(enable_flag)); 110 | #endif 111 | 112 | #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) 113 | # error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" 114 | #endif 115 | } 116 | 117 | // Send exactly n_bytes of the given data. 118 | // On error close the connection and throw. 119 | void send(const char *data, size_t n_bytes) 120 | { 121 | size_t bytes_sent = 0; 122 | while (bytes_sent < n_bytes) 123 | { 124 | #if defined(MSG_NOSIGNAL) 125 | const int send_flags = MSG_NOSIGNAL; 126 | #else 127 | const int send_flags = 0; 128 | #endif 129 | auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); 130 | if (write_result < 0) 131 | { 132 | close(); 133 | throw_spdlog_ex("write(2) failed", errno); 134 | } 135 | 136 | if (write_result == 0) // (probably should not happen but in any case..) 137 | { 138 | break; 139 | } 140 | bytes_sent += static_cast(write_result); 141 | } 142 | } 143 | }; 144 | } // namespace details 145 | } // namespace spdlog 146 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/thread_pool-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace details { 15 | 16 | SPDLOG_INLINE thread_pool::thread_pool( 17 | size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop) 18 | : q_(q_max_items) 19 | { 20 | if (threads_n == 0 || threads_n > 1000) 21 | { 22 | throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " 23 | "range is 1-1000)"); 24 | } 25 | for (size_t i = 0; i < threads_n; i++) 26 | { 27 | threads_.emplace_back([this, on_thread_start, on_thread_stop] { 28 | on_thread_start(); 29 | this->thread_pool::worker_loop_(); 30 | on_thread_stop(); 31 | }); 32 | } 33 | } 34 | 35 | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) 36 | : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) 37 | {} 38 | 39 | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) 40 | : thread_pool( 41 | q_max_items, threads_n, [] {}, [] {}) 42 | {} 43 | 44 | // message all threads to terminate gracefully join them 45 | SPDLOG_INLINE thread_pool::~thread_pool() 46 | { 47 | SPDLOG_TRY 48 | { 49 | for (size_t i = 0; i < threads_.size(); i++) 50 | { 51 | post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); 52 | } 53 | 54 | for (auto &t : threads_) 55 | { 56 | t.join(); 57 | } 58 | } 59 | SPDLOG_CATCH_STD 60 | } 61 | 62 | void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) 63 | { 64 | async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); 65 | post_async_msg_(std::move(async_m), overflow_policy); 66 | } 67 | 68 | void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) 69 | { 70 | post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); 71 | } 72 | 73 | size_t SPDLOG_INLINE thread_pool::overrun_counter() 74 | { 75 | return q_.overrun_counter(); 76 | } 77 | 78 | void SPDLOG_INLINE thread_pool::reset_overrun_counter() 79 | { 80 | q_.reset_overrun_counter(); 81 | } 82 | 83 | size_t SPDLOG_INLINE thread_pool::queue_size() 84 | { 85 | return q_.size(); 86 | } 87 | 88 | void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) 89 | { 90 | if (overflow_policy == async_overflow_policy::block) 91 | { 92 | q_.enqueue(std::move(new_msg)); 93 | } 94 | else 95 | { 96 | q_.enqueue_nowait(std::move(new_msg)); 97 | } 98 | } 99 | 100 | void SPDLOG_INLINE thread_pool::worker_loop_() 101 | { 102 | while (process_next_msg_()) {} 103 | } 104 | 105 | // process next message in the queue 106 | // return true if this thread should still be active (while no terminate msg 107 | // was received) 108 | bool SPDLOG_INLINE thread_pool::process_next_msg_() 109 | { 110 | async_msg incoming_async_msg; 111 | bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); 112 | if (!dequeued) 113 | { 114 | return true; 115 | } 116 | 117 | switch (incoming_async_msg.msg_type) 118 | { 119 | case async_msg_type::log: { 120 | incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); 121 | return true; 122 | } 123 | case async_msg_type::flush: { 124 | incoming_async_msg.worker_ptr->backend_flush_(); 125 | return true; 126 | } 127 | 128 | case async_msg_type::terminate: { 129 | return false; 130 | } 131 | 132 | default: { 133 | assert(false); 134 | } 135 | } 136 | 137 | return true; 138 | } 139 | 140 | } // namespace details 141 | } // namespace spdlog 142 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/thread_pool.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | class async_logger; 18 | 19 | namespace details { 20 | 21 | using async_logger_ptr = std::shared_ptr; 22 | 23 | enum class async_msg_type 24 | { 25 | log, 26 | flush, 27 | terminate 28 | }; 29 | 30 | // Async msg to move to/from the queue 31 | // Movable only. should never be copied 32 | struct async_msg : log_msg_buffer 33 | { 34 | async_msg_type msg_type{async_msg_type::log}; 35 | async_logger_ptr worker_ptr; 36 | 37 | async_msg() = default; 38 | ~async_msg() = default; 39 | 40 | // should only be moved in or out of the queue.. 41 | async_msg(const async_msg &) = delete; 42 | 43 | // support for vs2013 move 44 | #if defined(_MSC_VER) && _MSC_VER <= 1800 45 | async_msg(async_msg &&other) 46 | : log_msg_buffer(std::move(other)) 47 | , msg_type(other.msg_type) 48 | , worker_ptr(std::move(other.worker_ptr)) 49 | {} 50 | 51 | async_msg &operator=(async_msg &&other) 52 | { 53 | *static_cast(this) = std::move(other); 54 | msg_type = other.msg_type; 55 | worker_ptr = std::move(other.worker_ptr); 56 | return *this; 57 | } 58 | #else // (_MSC_VER) && _MSC_VER <= 1800 59 | async_msg(async_msg &&) = default; 60 | async_msg &operator=(async_msg &&) = default; 61 | #endif 62 | 63 | // construct from log_msg with given type 64 | async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) 65 | : log_msg_buffer{m} 66 | , msg_type{the_type} 67 | , worker_ptr{std::move(worker)} 68 | {} 69 | 70 | async_msg(async_logger_ptr &&worker, async_msg_type the_type) 71 | : log_msg_buffer{} 72 | , msg_type{the_type} 73 | , worker_ptr{std::move(worker)} 74 | {} 75 | 76 | explicit async_msg(async_msg_type the_type) 77 | : async_msg{nullptr, the_type} 78 | {} 79 | }; 80 | 81 | class SPDLOG_API thread_pool 82 | { 83 | public: 84 | using item_type = async_msg; 85 | using q_type = details::mpmc_blocking_queue; 86 | 87 | thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop); 88 | thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); 89 | thread_pool(size_t q_max_items, size_t threads_n); 90 | 91 | // message all threads to terminate gracefully and join them 92 | ~thread_pool(); 93 | 94 | thread_pool(const thread_pool &) = delete; 95 | thread_pool &operator=(thread_pool &&) = delete; 96 | 97 | void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy); 98 | void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); 99 | size_t overrun_counter(); 100 | void reset_overrun_counter(); 101 | size_t queue_size(); 102 | 103 | private: 104 | q_type q_; 105 | 106 | std::vector threads_; 107 | 108 | void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); 109 | void worker_loop_(); 110 | 111 | // process next message in the queue 112 | // return true if this thread should still be active (while no terminate msg 113 | // was received) 114 | bool process_next_msg_(); 115 | }; 116 | 117 | } // namespace details 118 | } // namespace spdlog 119 | 120 | #ifdef SPDLOG_HEADER_ONLY 121 | # include "thread_pool-inl.h" 122 | #endif 123 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/udp_client-windows.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Helper RAII over winsock udp client socket. 7 | // Will throw on construction if socket creation failed. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #pragma comment(lib, "Ws2_32.lib") 19 | #pragma comment(lib, "Mswsock.lib") 20 | #pragma comment(lib, "AdvApi32.lib") 21 | 22 | namespace spdlog { 23 | namespace details { 24 | class udp_client 25 | { 26 | static constexpr int TX_BUFFER_SIZE = 1024 * 10; 27 | SOCKET socket_ = INVALID_SOCKET; 28 | sockaddr_in addr_ = {0}; 29 | 30 | static void init_winsock_() 31 | { 32 | WSADATA wsaData; 33 | auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); 34 | if (rv != 0) 35 | { 36 | throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); 37 | } 38 | } 39 | 40 | static void throw_winsock_error_(const std::string &msg, int last_error) 41 | { 42 | char buf[512]; 43 | ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, 44 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); 45 | 46 | throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); 47 | } 48 | 49 | void cleanup_() 50 | { 51 | if (socket_ != INVALID_SOCKET) 52 | { 53 | ::closesocket(socket_); 54 | } 55 | socket_ = INVALID_SOCKET; 56 | ::WSACleanup(); 57 | } 58 | 59 | public: 60 | udp_client(const std::string &host, uint16_t port) 61 | { 62 | init_winsock_(); 63 | 64 | addr_.sin_family = PF_INET; 65 | addr_.sin_port = htons(port); 66 | addr_.sin_addr.s_addr = INADDR_ANY; 67 | if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) 68 | { 69 | int last_error = ::WSAGetLastError(); 70 | ::WSACleanup(); 71 | throw_winsock_error_("error: Invalid address!", last_error); 72 | } 73 | 74 | socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); 75 | if (socket_ == INVALID_SOCKET) 76 | { 77 | int last_error = ::WSAGetLastError(); 78 | ::WSACleanup(); 79 | throw_winsock_error_("error: Create Socket failed", last_error); 80 | } 81 | 82 | int option_value = TX_BUFFER_SIZE; 83 | if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) 84 | { 85 | int last_error = ::WSAGetLastError(); 86 | cleanup_(); 87 | throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); 88 | } 89 | } 90 | 91 | ~udp_client() 92 | { 93 | cleanup_(); 94 | } 95 | 96 | SOCKET fd() const 97 | { 98 | return socket_; 99 | } 100 | 101 | void send(const char *data, size_t n_bytes) 102 | { 103 | socklen_t tolen = sizeof(struct sockaddr); 104 | if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1) 105 | { 106 | throw_spdlog_ex("sendto(2) failed", errno); 107 | } 108 | } 109 | }; 110 | } // namespace details 111 | } // namespace spdlog 112 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/udp_client.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // Helper RAII over unix udp client socket. 7 | // Will throw on construction if the socket creation failed. 8 | 9 | #ifdef _WIN32 10 | # error "include udp_client-windows.h instead" 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace spdlog { 26 | namespace details { 27 | 28 | class udp_client 29 | { 30 | static constexpr int TX_BUFFER_SIZE = 1024 * 10; 31 | int socket_ = -1; 32 | struct sockaddr_in sockAddr_; 33 | 34 | void cleanup_() 35 | { 36 | if (socket_ != -1) 37 | { 38 | ::close(socket_); 39 | socket_ = -1; 40 | } 41 | } 42 | 43 | public: 44 | udp_client(const std::string &host, uint16_t port) 45 | { 46 | socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); 47 | if (socket_ < 0) 48 | { 49 | throw_spdlog_ex("error: Create Socket Failed!"); 50 | } 51 | 52 | int option_value = TX_BUFFER_SIZE; 53 | if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) 54 | { 55 | cleanup_(); 56 | throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); 57 | } 58 | 59 | sockAddr_.sin_family = AF_INET; 60 | sockAddr_.sin_port = htons(port); 61 | 62 | if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) 63 | { 64 | cleanup_(); 65 | throw_spdlog_ex("error: Invalid address!"); 66 | } 67 | 68 | ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); 69 | } 70 | 71 | ~udp_client() 72 | { 73 | cleanup_(); 74 | } 75 | 76 | int fd() const 77 | { 78 | return socket_; 79 | } 80 | 81 | // Send exactly n_bytes of the given data. 82 | // On error close the connection and throw. 83 | void send(const char *data, size_t n_bytes) 84 | { 85 | ssize_t toslen = 0; 86 | socklen_t tolen = sizeof(struct sockaddr); 87 | if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) 88 | { 89 | throw_spdlog_ex("sendto(2) failed", errno); 90 | } 91 | } 92 | }; 93 | } // namespace details 94 | } // namespace spdlog 95 | -------------------------------------------------------------------------------- /thirdpart/spdlog/details/windows_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | # define NOMINMAX // prevent windows redefining min/max 5 | #endif 6 | 7 | #ifndef WIN32_LEAN_AND_MEAN 8 | # define WIN32_LEAN_AND_MEAN 9 | #endif 10 | 11 | #include 12 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/bundled/fmt.license.rst: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/bundled/locale.h: -------------------------------------------------------------------------------- 1 | #include "xchar.h" 2 | #warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead 3 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/bundled/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | FMT_BEGIN_NAMESPACE 16 | 17 | template class basic_printf_context; 18 | 19 | namespace detail { 20 | 21 | // Checks if T has a user-defined operator<<. 22 | template 23 | class is_streamable { 24 | private: 25 | template 26 | static auto test(int) 27 | -> bool_constant&>() 28 | << std::declval()) != 0>; 29 | 30 | template static auto test(...) -> std::false_type; 31 | 32 | using result = decltype(test(0)); 33 | 34 | public: 35 | is_streamable() = default; 36 | 37 | static const bool value = result::value; 38 | }; 39 | 40 | // Formatting of built-in types and arrays is intentionally disabled because 41 | // it's handled by standard (non-ostream) formatters. 42 | template 43 | struct is_streamable< 44 | T, Char, 45 | enable_if_t< 46 | std::is_arithmetic::value || std::is_array::value || 47 | std::is_pointer::value || std::is_same::value || 48 | std::is_same>::value || 49 | std::is_same>::value || 50 | (std::is_convertible::value && !std::is_enum::value)>> 51 | : std::false_type {}; 52 | 53 | // Write the content of buf to os. 54 | // It is a separate function rather than a part of vprint to simplify testing. 55 | template 56 | void write_buffer(std::basic_ostream& os, buffer& buf) { 57 | const Char* buf_data = buf.data(); 58 | using unsigned_streamsize = std::make_unsigned::type; 59 | unsigned_streamsize size = buf.size(); 60 | unsigned_streamsize max_size = to_unsigned(max_value()); 61 | do { 62 | unsigned_streamsize n = size <= max_size ? size : max_size; 63 | os.write(buf_data, static_cast(n)); 64 | buf_data += n; 65 | size -= n; 66 | } while (size != 0); 67 | } 68 | 69 | template 70 | void format_value(buffer& buf, const T& value, 71 | locale_ref loc = locale_ref()) { 72 | auto&& format_buf = formatbuf>(buf); 73 | auto&& output = std::basic_ostream(&format_buf); 74 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 75 | if (loc) output.imbue(loc.get()); 76 | #endif 77 | output << value; 78 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 79 | buf.try_resize(buf.size()); 80 | } 81 | 82 | // Formats an object of type T that has an overloaded ostream operator<<. 83 | template 84 | struct fallback_formatter::value>> 85 | : private formatter, Char> { 86 | using formatter, Char>::parse; 87 | 88 | template 89 | auto format(const T& value, basic_format_context& ctx) 90 | -> OutputIt { 91 | auto buffer = basic_memory_buffer(); 92 | format_value(buffer, value, ctx.locale()); 93 | return formatter, Char>::format( 94 | {buffer.data(), buffer.size()}, ctx); 95 | } 96 | 97 | // DEPRECATED! 98 | template 99 | auto format(const T& value, basic_printf_context& ctx) 100 | -> OutputIt { 101 | auto buffer = basic_memory_buffer(); 102 | format_value(buffer, value, ctx.locale()); 103 | return std::copy(buffer.begin(), buffer.end(), ctx.out()); 104 | } 105 | }; 106 | } // namespace detail 107 | 108 | FMT_MODULE_EXPORT 109 | template 110 | void vprint(std::basic_ostream& os, basic_string_view format_str, 111 | basic_format_args>> args) { 112 | auto buffer = basic_memory_buffer(); 113 | detail::vformat_to(buffer, format_str, args); 114 | detail::write_buffer(os, buffer); 115 | } 116 | 117 | /** 118 | \rst 119 | Prints formatted data to the stream *os*. 120 | 121 | **Example**:: 122 | 123 | fmt::print(cerr, "Don't {}!", "panic"); 124 | \endrst 125 | */ 126 | FMT_MODULE_EXPORT 127 | template ::value, char_t>> 129 | void print(std::basic_ostream& os, const S& format_str, Args&&... args) { 130 | vprint(os, to_string_view(format_str), 131 | fmt::make_args_checked(format_str, args...)); 132 | } 133 | FMT_END_NAMESPACE 134 | 135 | #endif // FMT_OSTREAM_H_ 136 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/chrono.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's chrono support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's compile-time support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/fmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016-2018 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | // 9 | // Include a bundled header-only copy of fmtlib or an external one. 10 | // By default spdlog include its own copy. 11 | // 12 | 13 | #if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format 14 | # include 15 | #elif !defined(SPDLOG_FMT_EXTERNAL) 16 | # if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) 17 | # define FMT_HEADER_ONLY 18 | # endif 19 | # ifndef FMT_USE_WINDOWS_H 20 | # define FMT_USE_WINDOWS_H 0 21 | # endif 22 | // enable the 'n' flag in for backward compatibility with fmt 6.x 23 | # define FMT_DEPRECATED_N_SPECIFIER 24 | # include 25 | # include 26 | #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib 27 | # include 28 | # include 29 | #endif 30 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/ostr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ostream support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's ranges support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Gabi Melman. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | // 8 | // include bundled or external copy of fmtlib's xchar support 9 | // 10 | 11 | #if !defined(SPDLOG_USE_STD_FORMAT) 12 | # if !defined(SPDLOG_FMT_EXTERNAL) 13 | # ifdef SPDLOG_HEADER_ONLY 14 | # ifndef FMT_HEADER_ONLY 15 | # define FMT_HEADER_ONLY 16 | # endif 17 | # endif 18 | # include 19 | # else 20 | # include 21 | # endif 22 | #endif 23 | -------------------------------------------------------------------------------- /thirdpart/spdlog/formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | class formatter 12 | { 13 | public: 14 | virtual ~formatter() = default; 15 | virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; 16 | virtual std::unique_ptr clone() const = 0; 17 | }; 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /thirdpart/spdlog/fwd.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | namespace spdlog { 7 | class logger; 8 | class formatter; 9 | 10 | namespace sinks { 11 | class sink; 12 | } 13 | 14 | namespace level { 15 | enum level_enum : int; 16 | } 17 | 18 | } // namespace spdlog 19 | -------------------------------------------------------------------------------- /thirdpart/spdlog/libspdlog.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgpp-programer/Qcap/873ed95b9bec2d25cef0e31aa14d0bca86a745d0/thirdpart/spdlog/libspdlog.a -------------------------------------------------------------------------------- /thirdpart/spdlog/pattern_formatter.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace details { 21 | 22 | // padding information. 23 | struct padding_info 24 | { 25 | enum class pad_side 26 | { 27 | left, 28 | right, 29 | center 30 | }; 31 | 32 | padding_info() = default; 33 | padding_info(size_t width, padding_info::pad_side side, bool truncate) 34 | : width_(width) 35 | , side_(side) 36 | , truncate_(truncate) 37 | , enabled_(true) 38 | {} 39 | 40 | bool enabled() const 41 | { 42 | return enabled_; 43 | } 44 | size_t width_ = 0; 45 | pad_side side_ = pad_side::left; 46 | bool truncate_ = false; 47 | bool enabled_ = false; 48 | }; 49 | 50 | class SPDLOG_API flag_formatter 51 | { 52 | public: 53 | explicit flag_formatter(padding_info padinfo) 54 | : padinfo_(padinfo) 55 | {} 56 | flag_formatter() = default; 57 | virtual ~flag_formatter() = default; 58 | virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; 59 | 60 | protected: 61 | padding_info padinfo_; 62 | }; 63 | 64 | } // namespace details 65 | 66 | class SPDLOG_API custom_flag_formatter : public details::flag_formatter 67 | { 68 | public: 69 | virtual std::unique_ptr clone() const = 0; 70 | 71 | void set_padding_info(const details::padding_info &padding) 72 | { 73 | flag_formatter::padinfo_ = padding; 74 | } 75 | }; 76 | 77 | class SPDLOG_API pattern_formatter final : public formatter 78 | { 79 | public: 80 | using custom_flags = std::unordered_map>; 81 | 82 | explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, 83 | std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags()); 84 | 85 | // use default pattern is not given 86 | explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); 87 | 88 | pattern_formatter(const pattern_formatter &other) = delete; 89 | pattern_formatter &operator=(const pattern_formatter &other) = delete; 90 | 91 | std::unique_ptr clone() const override; 92 | void format(const details::log_msg &msg, memory_buf_t &dest) override; 93 | 94 | template 95 | pattern_formatter &add_flag(char flag, Args &&... args) 96 | { 97 | custom_handlers_[flag] = details::make_unique(std::forward(args)...); 98 | return *this; 99 | } 100 | void set_pattern(std::string pattern); 101 | void need_localtime(bool need = true); 102 | 103 | private: 104 | std::string pattern_; 105 | std::string eol_; 106 | pattern_time_type pattern_time_type_; 107 | bool need_localtime_; 108 | std::tm cached_tm_; 109 | std::chrono::seconds last_log_secs_; 110 | std::vector> formatters_; 111 | custom_flags custom_handlers_; 112 | 113 | std::tm get_time_(const details::log_msg &msg); 114 | template 115 | void handle_flag_(char flag, details::padding_info padding); 116 | 117 | // Extract given pad spec (e.g. %8X) 118 | // Advance the given it pass the end of the padding spec found (if any) 119 | // Return padding. 120 | static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); 121 | 122 | void compile_pattern_(const std::string &pattern); 123 | }; 124 | } // namespace spdlog 125 | 126 | #ifdef SPDLOG_HEADER_ONLY 127 | # include "pattern_formatter-inl.h" 128 | #endif 129 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/android_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef __ANDROID__ 7 | 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | 14 | # include 15 | # include 16 | # include 17 | # include 18 | # include 19 | # include 20 | 21 | # if !defined(SPDLOG_ANDROID_RETRIES) 22 | # define SPDLOG_ANDROID_RETRIES 2 23 | # endif 24 | 25 | namespace spdlog { 26 | namespace sinks { 27 | 28 | /* 29 | * Android sink 30 | * (logging using __android_log_write or __android_log_buf_write depending on the specified BufferID) 31 | */ 32 | template 33 | class android_sink final : public base_sink 34 | { 35 | public: 36 | explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) 37 | : tag_(std::move(tag)) 38 | , use_raw_msg_(use_raw_msg) 39 | {} 40 | 41 | protected: 42 | void sink_it_(const details::log_msg &msg) override 43 | { 44 | const android_LogPriority priority = convert_to_android_(msg.level); 45 | memory_buf_t formatted; 46 | if (use_raw_msg_) 47 | { 48 | details::fmt_helper::append_string_view(msg.payload, formatted); 49 | } 50 | else 51 | { 52 | base_sink::formatter_->format(msg, formatted); 53 | } 54 | formatted.push_back('\0'); 55 | const char *msg_output = formatted.data(); 56 | 57 | // See system/core/liblog/logger_write.c for explanation of return value 58 | int ret = android_log(priority, tag_.c_str(), msg_output); 59 | int retry_count = 0; 60 | while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) 61 | { 62 | details::os::sleep_for_millis(5); 63 | ret = android_log(priority, tag_.c_str(), msg_output); 64 | retry_count++; 65 | } 66 | 67 | if (ret < 0) 68 | { 69 | throw_spdlog_ex("logging to Android failed", ret); 70 | } 71 | } 72 | 73 | void flush_() override {} 74 | 75 | private: 76 | // There might be liblog versions used, that do not support __android_log_buf_write. So we only compile and link against 77 | // __android_log_buf_write, if user explicitely provides a non-default log buffer. Otherwise, when using the default log buffer, always 78 | // log via __android_log_write. 79 | template 80 | typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) 81 | { 82 | return __android_log_write(prio, tag, text); 83 | } 84 | 85 | template 86 | typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) 87 | { 88 | return __android_log_buf_write(ID, prio, tag, text); 89 | } 90 | 91 | static android_LogPriority convert_to_android_(spdlog::level::level_enum level) 92 | { 93 | switch (level) 94 | { 95 | case spdlog::level::trace: 96 | return ANDROID_LOG_VERBOSE; 97 | case spdlog::level::debug: 98 | return ANDROID_LOG_DEBUG; 99 | case spdlog::level::info: 100 | return ANDROID_LOG_INFO; 101 | case spdlog::level::warn: 102 | return ANDROID_LOG_WARN; 103 | case spdlog::level::err: 104 | return ANDROID_LOG_ERROR; 105 | case spdlog::level::critical: 106 | return ANDROID_LOG_FATAL; 107 | default: 108 | return ANDROID_LOG_DEFAULT; 109 | } 110 | } 111 | 112 | std::string tag_; 113 | bool use_raw_msg_; 114 | }; 115 | 116 | using android_sink_mt = android_sink; 117 | using android_sink_st = android_sink; 118 | 119 | template 120 | using android_sink_buf_mt = android_sink; 121 | template 122 | using android_sink_buf_st = android_sink; 123 | 124 | } // namespace sinks 125 | 126 | // Create and register android syslog logger 127 | 128 | template 129 | inline std::shared_ptr android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") 130 | { 131 | return Factory::template create(logger_name, tag); 132 | } 133 | 134 | template 135 | inline std::shared_ptr android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") 136 | { 137 | return Factory::template create(logger_name, tag); 138 | } 139 | 140 | } // namespace spdlog 141 | 142 | #endif // __ANDROID__ -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/ansicolor_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, color_mode mode) 18 | : target_file_(target_file) 19 | , mutex_(ConsoleMutex::mutex()) 20 | , formatter_(details::make_unique()) 21 | 22 | { 23 | set_color_mode(mode); 24 | colors_[level::trace] = to_string_(white); 25 | colors_[level::debug] = to_string_(cyan); 26 | colors_[level::info] = to_string_(green); 27 | colors_[level::warn] = to_string_(yellow_bold); 28 | colors_[level::err] = to_string_(red_bold); 29 | colors_[level::critical] = to_string_(bold_on_red); 30 | colors_[level::off] = to_string_(reset); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) 35 | { 36 | std::lock_guard lock(mutex_); 37 | colors_[static_cast(color_level)] = to_string_(color); 38 | } 39 | 40 | template 41 | SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg) 42 | { 43 | // Wrap the originally formatted message in color codes. 44 | // If color is not supported in the terminal, log as is instead. 45 | std::lock_guard lock(mutex_); 46 | msg.color_range_start = 0; 47 | msg.color_range_end = 0; 48 | memory_buf_t formatted; 49 | formatter_->format(msg, formatted); 50 | if (should_do_colors_ && msg.color_range_end > msg.color_range_start) 51 | { 52 | // before color range 53 | print_range_(formatted, 0, msg.color_range_start); 54 | // in color range 55 | print_ccode_(colors_[static_cast(msg.level)]); 56 | print_range_(formatted, msg.color_range_start, msg.color_range_end); 57 | print_ccode_(reset); 58 | // after color range 59 | print_range_(formatted, msg.color_range_end, formatted.size()); 60 | } 61 | else // no color 62 | { 63 | print_range_(formatted, 0, formatted.size()); 64 | } 65 | fflush(target_file_); 66 | } 67 | 68 | template 69 | SPDLOG_INLINE void ansicolor_sink::flush() 70 | { 71 | std::lock_guard lock(mutex_); 72 | fflush(target_file_); 73 | } 74 | 75 | template 76 | SPDLOG_INLINE void ansicolor_sink::set_pattern(const std::string &pattern) 77 | { 78 | std::lock_guard lock(mutex_); 79 | formatter_ = std::unique_ptr(new pattern_formatter(pattern)); 80 | } 81 | 82 | template 83 | SPDLOG_INLINE void ansicolor_sink::set_formatter(std::unique_ptr sink_formatter) 84 | { 85 | std::lock_guard lock(mutex_); 86 | formatter_ = std::move(sink_formatter); 87 | } 88 | 89 | template 90 | SPDLOG_INLINE bool ansicolor_sink::should_color() 91 | { 92 | return should_do_colors_; 93 | } 94 | 95 | template 96 | SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) 97 | { 98 | switch (mode) 99 | { 100 | case color_mode::always: 101 | should_do_colors_ = true; 102 | return; 103 | case color_mode::automatic: 104 | should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); 105 | return; 106 | case color_mode::never: 107 | should_do_colors_ = false; 108 | return; 109 | default: 110 | should_do_colors_ = false; 111 | } 112 | } 113 | 114 | template 115 | SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) 116 | { 117 | fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); 118 | } 119 | 120 | template 121 | SPDLOG_INLINE void ansicolor_sink::print_range_(const memory_buf_t &formatted, size_t start, size_t end) 122 | { 123 | fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); 124 | } 125 | 126 | template 127 | SPDLOG_INLINE std::string ansicolor_sink::to_string_(const string_view_t &sv) 128 | { 129 | return std::string(sv.data(), sv.size()); 130 | } 131 | 132 | // ansicolor_stdout_sink 133 | template 134 | SPDLOG_INLINE ansicolor_stdout_sink::ansicolor_stdout_sink(color_mode mode) 135 | : ansicolor_sink(stdout, mode) 136 | {} 137 | 138 | // ansicolor_stderr_sink 139 | template 140 | SPDLOG_INLINE ansicolor_stderr_sink::ansicolor_stderr_sink(color_mode mode) 141 | : ansicolor_sink(stderr, mode) 142 | {} 143 | 144 | } // namespace sinks 145 | } // namespace spdlog 146 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/ansicolor_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | 17 | /** 18 | * This sink prefixes the output with an ANSI escape sequence color code 19 | * depending on the severity 20 | * of the message. 21 | * If no color terminal detected, omit the escape codes. 22 | */ 23 | 24 | template 25 | class ansicolor_sink : public sink 26 | { 27 | public: 28 | using mutex_t = typename ConsoleMutex::mutex_t; 29 | ansicolor_sink(FILE *target_file, color_mode mode); 30 | ~ansicolor_sink() override = default; 31 | 32 | ansicolor_sink(const ansicolor_sink &other) = delete; 33 | ansicolor_sink(ansicolor_sink &&other) = delete; 34 | 35 | ansicolor_sink &operator=(const ansicolor_sink &other) = delete; 36 | ansicolor_sink &operator=(ansicolor_sink &&other) = delete; 37 | 38 | void set_color(level::level_enum color_level, string_view_t color); 39 | void set_color_mode(color_mode mode); 40 | bool should_color(); 41 | 42 | void log(const details::log_msg &msg) override; 43 | void flush() override; 44 | void set_pattern(const std::string &pattern) final; 45 | void set_formatter(std::unique_ptr sink_formatter) override; 46 | 47 | // Formatting codes 48 | const string_view_t reset = "\033[m"; 49 | const string_view_t bold = "\033[1m"; 50 | const string_view_t dark = "\033[2m"; 51 | const string_view_t underline = "\033[4m"; 52 | const string_view_t blink = "\033[5m"; 53 | const string_view_t reverse = "\033[7m"; 54 | const string_view_t concealed = "\033[8m"; 55 | const string_view_t clear_line = "\033[K"; 56 | 57 | // Foreground colors 58 | const string_view_t black = "\033[30m"; 59 | const string_view_t red = "\033[31m"; 60 | const string_view_t green = "\033[32m"; 61 | const string_view_t yellow = "\033[33m"; 62 | const string_view_t blue = "\033[34m"; 63 | const string_view_t magenta = "\033[35m"; 64 | const string_view_t cyan = "\033[36m"; 65 | const string_view_t white = "\033[37m"; 66 | 67 | /// Background colors 68 | const string_view_t on_black = "\033[40m"; 69 | const string_view_t on_red = "\033[41m"; 70 | const string_view_t on_green = "\033[42m"; 71 | const string_view_t on_yellow = "\033[43m"; 72 | const string_view_t on_blue = "\033[44m"; 73 | const string_view_t on_magenta = "\033[45m"; 74 | const string_view_t on_cyan = "\033[46m"; 75 | const string_view_t on_white = "\033[47m"; 76 | 77 | /// Bold colors 78 | const string_view_t yellow_bold = "\033[33m\033[1m"; 79 | const string_view_t red_bold = "\033[31m\033[1m"; 80 | const string_view_t bold_on_red = "\033[1m\033[41m"; 81 | 82 | private: 83 | FILE *target_file_; 84 | mutex_t &mutex_; 85 | bool should_do_colors_; 86 | std::unique_ptr formatter_; 87 | std::array colors_; 88 | void print_ccode_(const string_view_t &color_code); 89 | void print_range_(const memory_buf_t &formatted, size_t start, size_t end); 90 | static std::string to_string_(const string_view_t &sv); 91 | }; 92 | 93 | template 94 | class ansicolor_stdout_sink : public ansicolor_sink 95 | { 96 | public: 97 | explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); 98 | }; 99 | 100 | template 101 | class ansicolor_stderr_sink : public ansicolor_sink 102 | { 103 | public: 104 | explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); 105 | }; 106 | 107 | using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; 108 | using ansicolor_stdout_sink_st = ansicolor_stdout_sink; 109 | 110 | using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; 111 | using ansicolor_stderr_sink_st = ansicolor_stderr_sink; 112 | 113 | } // namespace sinks 114 | } // namespace spdlog 115 | 116 | #ifdef SPDLOG_HEADER_ONLY 117 | # include "ansicolor_sink-inl.h" 118 | #endif 119 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/base_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | template 16 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() 17 | : formatter_{details::make_unique()} 18 | {} 19 | 20 | template 21 | SPDLOG_INLINE spdlog::sinks::base_sink::base_sink(std::unique_ptr formatter) 22 | : formatter_{std::move(formatter)} 23 | {} 24 | 25 | template 26 | void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) 27 | { 28 | std::lock_guard lock(mutex_); 29 | sink_it_(msg); 30 | } 31 | 32 | template 33 | void SPDLOG_INLINE spdlog::sinks::base_sink::flush() 34 | { 35 | std::lock_guard lock(mutex_); 36 | flush_(); 37 | } 38 | 39 | template 40 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) 41 | { 42 | std::lock_guard lock(mutex_); 43 | set_pattern_(pattern); 44 | } 45 | 46 | template 47 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) 48 | { 49 | std::lock_guard lock(mutex_); 50 | set_formatter_(std::move(sink_formatter)); 51 | } 52 | 53 | template 54 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) 55 | { 56 | set_formatter_(details::make_unique(pattern)); 57 | } 58 | 59 | template 60 | void SPDLOG_INLINE spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) 61 | { 62 | formatter_ = std::move(sink_formatter); 63 | } 64 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/base_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | // 6 | // base sink templated over a mutex (either dummy or real) 7 | // concrete implementation should override the sink_it_() and flush_() methods. 8 | // locking is taken care of in this class - no locking needed by the 9 | // implementers.. 10 | // 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | template 19 | class SPDLOG_API base_sink : public sink 20 | { 21 | public: 22 | base_sink(); 23 | explicit base_sink(std::unique_ptr formatter); 24 | ~base_sink() override = default; 25 | 26 | base_sink(const base_sink &) = delete; 27 | base_sink(base_sink &&) = delete; 28 | 29 | base_sink &operator=(const base_sink &) = delete; 30 | base_sink &operator=(base_sink &&) = delete; 31 | 32 | void log(const details::log_msg &msg) final; 33 | void flush() final; 34 | void set_pattern(const std::string &pattern) final; 35 | void set_formatter(std::unique_ptr sink_formatter) final; 36 | 37 | protected: 38 | // sink formatter 39 | std::unique_ptr formatter_; 40 | Mutex mutex_; 41 | 42 | virtual void sink_it_(const details::log_msg &msg) = 0; 43 | virtual void flush_() = 0; 44 | virtual void set_pattern_(const std::string &pattern); 45 | virtual void set_formatter_(std::unique_ptr sink_formatter); 46 | }; 47 | } // namespace sinks 48 | } // namespace spdlog 49 | 50 | #ifdef SPDLOG_HEADER_ONLY 51 | # include "base_sink-inl.h" 52 | #endif 53 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/basic_file_sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers) 18 | : file_helper_{event_handlers} 19 | { 20 | file_helper_.open(filename, truncate); 21 | } 22 | 23 | template 24 | SPDLOG_INLINE const filename_t &basic_file_sink::filename() const 25 | { 26 | return file_helper_.filename(); 27 | } 28 | 29 | template 30 | SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) 31 | { 32 | memory_buf_t formatted; 33 | base_sink::formatter_->format(msg, formatted); 34 | file_helper_.write(formatted); 35 | } 36 | 37 | template 38 | SPDLOG_INLINE void basic_file_sink::flush_() 39 | { 40 | file_helper_.flush(); 41 | } 42 | 43 | } // namespace sinks 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/basic_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /* 17 | * Trivial file sink with single file as target 18 | */ 19 | template 20 | class basic_file_sink final : public base_sink 21 | { 22 | public: 23 | explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); 24 | const filename_t &filename() const; 25 | 26 | protected: 27 | void sink_it_(const details::log_msg &msg) override; 28 | void flush_() override; 29 | 30 | private: 31 | details::file_helper file_helper_; 32 | }; 33 | 34 | using basic_file_sink_mt = basic_file_sink; 35 | using basic_file_sink_st = basic_file_sink; 36 | 37 | } // namespace sinks 38 | 39 | // 40 | // factory functions 41 | // 42 | template 43 | inline std::shared_ptr basic_logger_mt( 44 | const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) 45 | { 46 | return Factory::template create(logger_name, filename, truncate, event_handlers); 47 | } 48 | 49 | template 50 | inline std::shared_ptr basic_logger_st( 51 | const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) 52 | { 53 | return Factory::template create(logger_name, filename, truncate, event_handlers); 54 | } 55 | 56 | } // namespace spdlog 57 | 58 | #ifdef SPDLOG_HEADER_ONLY 59 | # include "basic_file_sink-inl.h" 60 | #endif 61 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/dist_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "base_sink.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Distribution sink (mux). Stores a vector of sinks which get called when log 17 | // is called 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | 22 | template 23 | class dist_sink : public base_sink 24 | { 25 | public: 26 | dist_sink() = default; 27 | explicit dist_sink(std::vector> sinks) 28 | : sinks_(sinks) 29 | {} 30 | 31 | dist_sink(const dist_sink &) = delete; 32 | dist_sink &operator=(const dist_sink &) = delete; 33 | 34 | void add_sink(std::shared_ptr sink) 35 | { 36 | std::lock_guard lock(base_sink::mutex_); 37 | sinks_.push_back(sink); 38 | } 39 | 40 | void remove_sink(std::shared_ptr sink) 41 | { 42 | std::lock_guard lock(base_sink::mutex_); 43 | sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); 44 | } 45 | 46 | void set_sinks(std::vector> sinks) 47 | { 48 | std::lock_guard lock(base_sink::mutex_); 49 | sinks_ = std::move(sinks); 50 | } 51 | 52 | std::vector> &sinks() 53 | { 54 | return sinks_; 55 | } 56 | 57 | protected: 58 | void sink_it_(const details::log_msg &msg) override 59 | { 60 | for (auto &sink : sinks_) 61 | { 62 | if (sink->should_log(msg.level)) 63 | { 64 | sink->log(msg); 65 | } 66 | } 67 | } 68 | 69 | void flush_() override 70 | { 71 | for (auto &sink : sinks_) 72 | { 73 | sink->flush(); 74 | } 75 | } 76 | 77 | void set_pattern_(const std::string &pattern) override 78 | { 79 | set_formatter_(details::make_unique(pattern)); 80 | } 81 | 82 | void set_formatter_(std::unique_ptr sink_formatter) override 83 | { 84 | base_sink::formatter_ = std::move(sink_formatter); 85 | for (auto &sink : sinks_) 86 | { 87 | sink->set_formatter(base_sink::formatter_->clone()); 88 | } 89 | } 90 | std::vector> sinks_; 91 | }; 92 | 93 | using dist_sink_mt = dist_sink; 94 | using dist_sink_st = dist_sink; 95 | 96 | } // namespace sinks 97 | } // namespace spdlog 98 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/dup_filter_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "dist_sink.h" 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Duplicate message removal sink. 16 | // Skip the message if previous one is identical and less than "max_skip_duration" have passed 17 | // 18 | // Example: 19 | // 20 | // #include 21 | // 22 | // int main() { 23 | // auto dup_filter = std::make_shared(std::chrono::seconds(5)); 24 | // dup_filter->add_sink(std::make_shared()); 25 | // spdlog::logger l("logger", dup_filter); 26 | // l.info("Hello"); 27 | // l.info("Hello"); 28 | // l.info("Hello"); 29 | // l.info("Different Hello"); 30 | // } 31 | // 32 | // Will produce: 33 | // [2019-06-25 17:50:56.511] [logger] [info] Hello 34 | // [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. 35 | // [2019-06-25 17:50:56.512] [logger] [info] Different Hello 36 | 37 | namespace spdlog { 38 | namespace sinks { 39 | template 40 | class dup_filter_sink : public dist_sink 41 | { 42 | public: 43 | template 44 | explicit dup_filter_sink(std::chrono::duration max_skip_duration) 45 | : max_skip_duration_{max_skip_duration} 46 | {} 47 | 48 | protected: 49 | std::chrono::microseconds max_skip_duration_; 50 | log_clock::time_point last_msg_time_; 51 | std::string last_msg_payload_; 52 | size_t skip_counter_ = 0; 53 | 54 | void sink_it_(const details::log_msg &msg) override 55 | { 56 | bool filtered = filter_(msg); 57 | if (!filtered) 58 | { 59 | skip_counter_ += 1; 60 | return; 61 | } 62 | 63 | // log the "skipped.." message 64 | if (skip_counter_ > 0) 65 | { 66 | char buf[64]; 67 | auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast(skip_counter_)); 68 | if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) 69 | { 70 | details::log_msg skipped_msg{msg.logger_name, level::info, string_view_t{buf, static_cast(msg_size)}}; 71 | dist_sink::sink_it_(skipped_msg); 72 | } 73 | } 74 | 75 | // log current message 76 | dist_sink::sink_it_(msg); 77 | last_msg_time_ = msg.time; 78 | skip_counter_ = 0; 79 | last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); 80 | } 81 | 82 | // return whether the log msg should be displayed (true) or skipped (false) 83 | bool filter_(const details::log_msg &msg) 84 | { 85 | auto filter_duration = msg.time - last_msg_time_; 86 | return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); 87 | } 88 | }; 89 | 90 | using dup_filter_sink_mt = dup_filter_sink; 91 | using dup_filter_sink_st = dup_filter_sink; 92 | 93 | } // namespace sinks 94 | } // namespace spdlog 95 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/mongo_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // 7 | // Custom sink for mongodb 8 | // Building and using requires mongocxx library. 9 | // For building mongocxx library check the url below 10 | // http://mongocxx.org/mongocxx-v3/installation/ 11 | // 12 | 13 | #include "spdlog/common.h" 14 | #include "spdlog/details/log_msg.h" 15 | #include "spdlog/sinks/base_sink.h" 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace spdlog { 27 | namespace sinks { 28 | template 29 | class mongo_sink : public base_sink 30 | { 31 | public: 32 | mongo_sink(const std::string &db_name, const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") 33 | { 34 | try 35 | { 36 | client_ = spdlog::details::make_unique(mongocxx::uri{uri}); 37 | db_name_ = db_name; 38 | coll_name_ = collection_name; 39 | } 40 | catch (const std::exception) 41 | { 42 | throw spdlog_ex("Error opening database"); 43 | } 44 | } 45 | 46 | ~mongo_sink() 47 | { 48 | flush_(); 49 | } 50 | 51 | protected: 52 | void sink_it_(const details::log_msg &msg) override 53 | { 54 | using bsoncxx::builder::stream::document; 55 | using bsoncxx::builder::stream::finalize; 56 | 57 | if (client_ != nullptr) 58 | { 59 | auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level" << level::to_string_view(msg.level).data() 60 | << "message" << std::string(msg.payload.begin(), msg.payload.end()) << "logger_name" 61 | << std::string(msg.logger_name.begin(), msg.logger_name.end()) << "thread_id" 62 | << static_cast(msg.thread_id) << finalize; 63 | client_->database(db_name_).collection(coll_name_).insert_one(doc.view()); 64 | } 65 | } 66 | 67 | void flush_() override {} 68 | 69 | private: 70 | static mongocxx::instance instance_; 71 | std::string db_name_; 72 | std::string coll_name_; 73 | std::unique_ptr client_ = nullptr; 74 | }; 75 | template<> 76 | mongocxx::instance mongo_sink::instance_{}; 77 | 78 | #include "spdlog/details/null_mutex.h" 79 | #include 80 | using mongo_sink_mt = mongo_sink; 81 | using mongo_sink_st = mongo_sink; 82 | 83 | } // namespace sinks 84 | 85 | template 86 | inline std::shared_ptr mongo_logger_mt(const std::string &logger_name, const std::string &db_name, 87 | const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") 88 | { 89 | return Factory::template create(logger_name, db_name, collection_name, uri); 90 | } 91 | 92 | template 93 | inline std::shared_ptr mongo_logger_st(const std::string &logger_name, const std::string &db_name, 94 | const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") 95 | { 96 | return Factory::template create(logger_name, db_name, collection_name, uri); 97 | } 98 | 99 | } // namespace spdlog 100 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/msvc_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2016 Alexander Dalshov. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #if defined(_WIN32) 7 | 8 | # include 9 | # include 10 | 11 | # include 12 | # include 13 | 14 | // Avoid including windows.h (https://stackoverflow.com/a/30741042) 15 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); 16 | 17 | namespace spdlog { 18 | namespace sinks { 19 | /* 20 | * MSVC sink (logging using OutputDebugStringA) 21 | */ 22 | template 23 | class msvc_sink : public base_sink 24 | { 25 | public: 26 | msvc_sink() = default; 27 | 28 | protected: 29 | void sink_it_(const details::log_msg &msg) override 30 | { 31 | memory_buf_t formatted; 32 | base_sink::formatter_->format(msg, formatted); 33 | formatted.push_back('\0'); // add a null terminator for OutputDebugStringA 34 | OutputDebugStringA(formatted.data()); 35 | } 36 | 37 | void flush_() override {} 38 | }; 39 | 40 | using msvc_sink_mt = msvc_sink; 41 | using msvc_sink_st = msvc_sink; 42 | 43 | using windebug_sink_mt = msvc_sink_mt; 44 | using windebug_sink_st = msvc_sink_st; 45 | 46 | } // namespace sinks 47 | } // namespace spdlog 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/null_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | template 16 | class null_sink : public base_sink 17 | { 18 | protected: 19 | void sink_it_(const details::log_msg &) override {} 20 | void flush_() override {} 21 | }; 22 | 23 | using null_sink_mt = null_sink; 24 | using null_sink_st = null_sink; 25 | 26 | } // namespace sinks 27 | 28 | template 29 | inline std::shared_ptr null_logger_mt(const std::string &logger_name) 30 | { 31 | auto null_logger = Factory::template create(logger_name); 32 | null_logger->set_level(level::off); 33 | return null_logger; 34 | } 35 | 36 | template 37 | inline std::shared_ptr null_logger_st(const std::string &logger_name) 38 | { 39 | auto null_logger = Factory::template create(logger_name); 40 | null_logger->set_level(level::off); 41 | return null_logger; 42 | } 43 | 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/ostream_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | template 15 | class ostream_sink final : public base_sink 16 | { 17 | public: 18 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 19 | : ostream_(os) 20 | , force_flush_(force_flush) 21 | {} 22 | ostream_sink(const ostream_sink &) = delete; 23 | ostream_sink &operator=(const ostream_sink &) = delete; 24 | 25 | protected: 26 | void sink_it_(const details::log_msg &msg) override 27 | { 28 | memory_buf_t formatted; 29 | base_sink::formatter_->format(msg, formatted); 30 | ostream_.write(formatted.data(), static_cast(formatted.size())); 31 | if (force_flush_) 32 | { 33 | ostream_.flush(); 34 | } 35 | } 36 | 37 | void flush_() override 38 | { 39 | ostream_.flush(); 40 | } 41 | 42 | std::ostream &ostream_; 43 | bool force_flush_; 44 | }; 45 | 46 | using ostream_sink_mt = ostream_sink; 47 | using ostream_sink_st = ostream_sink; 48 | 49 | } // namespace sinks 50 | } // namespace spdlog 51 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/qt_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman, mguludag and spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | // 7 | // Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... 8 | // etc) Building and using requires Qt library. 9 | // 10 | 11 | #include "spdlog/common.h" 12 | #include "spdlog/details/log_msg.h" 13 | #include "spdlog/details/synchronous_factory.h" 14 | #include "spdlog/sinks/base_sink.h" 15 | 16 | #include 17 | #include 18 | 19 | // 20 | // qt_sink class 21 | // 22 | namespace spdlog { 23 | namespace sinks { 24 | template 25 | class qt_sink : public base_sink 26 | { 27 | public: 28 | qt_sink(QObject *qt_object, const std::string &meta_method) 29 | { 30 | qt_object_ = qt_object; 31 | meta_method_ = meta_method; 32 | } 33 | 34 | ~qt_sink() 35 | { 36 | flush_(); 37 | } 38 | 39 | protected: 40 | void sink_it_(const details::log_msg &msg) override 41 | { 42 | memory_buf_t formatted; 43 | base_sink::formatter_->format(msg, formatted); 44 | string_view_t str = string_view_t(formatted.data(), formatted.size()); 45 | QMetaObject::invokeMethod(qt_object_, meta_method_.c_str(), Qt::AutoConnection, 46 | Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); 47 | } 48 | 49 | void flush_() override {} 50 | 51 | private: 52 | QObject *qt_object_ = nullptr; 53 | std::string meta_method_; 54 | }; 55 | 56 | #include "spdlog/details/null_mutex.h" 57 | #include 58 | using qt_sink_mt = qt_sink; 59 | using qt_sink_st = qt_sink; 60 | } // namespace sinks 61 | 62 | // 63 | // Factory functions 64 | // 65 | template 66 | inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") 67 | { 68 | return Factory::template create(logger_name, qt_object, meta_method); 69 | } 70 | 71 | template 72 | inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") 73 | { 74 | return Factory::template create(logger_name, qt_object, meta_method); 75 | } 76 | 77 | template 78 | inline std::shared_ptr qt_logger_mt( 79 | const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") 80 | { 81 | return Factory::template create(logger_name, qt_object, meta_method); 82 | } 83 | 84 | template 85 | inline std::shared_ptr qt_logger_st( 86 | const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") 87 | { 88 | return Factory::template create(logger_name, qt_object, meta_method); 89 | } 90 | 91 | template 92 | inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) 93 | { 94 | return Factory::template create(logger_name, qt_object, meta_method); 95 | } 96 | 97 | template 98 | inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) 99 | { 100 | return Factory::template create(logger_name, qt_object, meta_method); 101 | } 102 | } // namespace spdlog 103 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/ringbuffer_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include "spdlog/sinks/base_sink.h" 7 | #include "spdlog/details/circular_q.h" 8 | #include "spdlog/details/log_msg_buffer.h" 9 | #include "spdlog/details/null_mutex.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | /* 18 | * Ring buffer sink 19 | */ 20 | template 21 | class ringbuffer_sink final : public base_sink 22 | { 23 | public: 24 | explicit ringbuffer_sink(size_t n_items) 25 | : q_{n_items} 26 | {} 27 | 28 | std::vector last_raw(size_t lim = 0) 29 | { 30 | std::lock_guard lock(base_sink::mutex_); 31 | auto items_available = q_.size(); 32 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 33 | std::vector ret; 34 | ret.reserve(n_items); 35 | for (size_t i = (items_available - n_items); i < items_available; i++) 36 | { 37 | ret.push_back(q_.at(i)); 38 | } 39 | return ret; 40 | } 41 | 42 | std::vector last_formatted(size_t lim = 0) 43 | { 44 | std::lock_guard lock(base_sink::mutex_); 45 | auto items_available = q_.size(); 46 | auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; 47 | std::vector ret; 48 | ret.reserve(n_items); 49 | for (size_t i = (items_available - n_items); i < items_available; i++) 50 | { 51 | memory_buf_t formatted; 52 | base_sink::formatter_->format(q_.at(i), formatted); 53 | ret.push_back(std::move(SPDLOG_BUF_TO_STRING(formatted))); 54 | } 55 | return ret; 56 | } 57 | 58 | protected: 59 | void sink_it_(const details::log_msg &msg) override 60 | { 61 | q_.push_back(details::log_msg_buffer{msg}); 62 | } 63 | void flush_() override {} 64 | 65 | private: 66 | details::circular_q q_; 67 | }; 68 | 69 | using ringbuffer_sink_mt = ringbuffer_sink; 70 | using ringbuffer_sink_st = ringbuffer_sink; 71 | 72 | } // namespace sinks 73 | 74 | } // namespace spdlog 75 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/rotating_file_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | 18 | // 19 | // Rotating file sink based on size 20 | // 21 | template 22 | class rotating_file_sink final : public base_sink 23 | { 24 | public: 25 | rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, 26 | const file_event_handlers &event_handlers = {}); 27 | static filename_t calc_filename(const filename_t &filename, std::size_t index); 28 | filename_t filename(); 29 | 30 | protected: 31 | void sink_it_(const details::log_msg &msg) override; 32 | void flush_() override; 33 | 34 | private: 35 | // Rotate files: 36 | // log.txt -> log.1.txt 37 | // log.1.txt -> log.2.txt 38 | // log.2.txt -> log.3.txt 39 | // log.3.txt -> delete 40 | void rotate_(); 41 | 42 | // delete the target if exists, and rename the src file to target 43 | // return true on success, false otherwise. 44 | bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); 45 | 46 | filename_t base_filename_; 47 | std::size_t max_size_; 48 | std::size_t max_files_; 49 | std::size_t current_size_; 50 | details::file_helper file_helper_; 51 | }; 52 | 53 | using rotating_file_sink_mt = rotating_file_sink; 54 | using rotating_file_sink_st = rotating_file_sink; 55 | 56 | } // namespace sinks 57 | 58 | // 59 | // factory functions 60 | // 61 | 62 | template 63 | inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, const filename_t &filename, size_t max_file_size, 64 | size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) 65 | { 66 | return Factory::template create( 67 | logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); 68 | } 69 | 70 | template 71 | inline std::shared_ptr rotating_logger_st(const std::string &logger_name, const filename_t &filename, size_t max_file_size, 72 | size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) 73 | { 74 | return Factory::template create( 75 | logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); 76 | } 77 | } // namespace spdlog 78 | 79 | #ifdef SPDLOG_HEADER_ONLY 80 | # include "rotating_file_sink-inl.h" 81 | #endif 82 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/sink-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | 12 | SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const 13 | { 14 | return msg_level >= level_.load(std::memory_order_relaxed); 15 | } 16 | 17 | SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) 18 | { 19 | level_.store(log_level, std::memory_order_relaxed); 20 | } 21 | 22 | SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const 23 | { 24 | return static_cast(level_.load(std::memory_order_relaxed)); 25 | } 26 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | namespace spdlog { 10 | 11 | namespace sinks { 12 | class SPDLOG_API sink 13 | { 14 | public: 15 | virtual ~sink() = default; 16 | virtual void log(const details::log_msg &msg) = 0; 17 | virtual void flush() = 0; 18 | virtual void set_pattern(const std::string &pattern) = 0; 19 | virtual void set_formatter(std::unique_ptr sink_formatter) = 0; 20 | 21 | void set_level(level::level_enum log_level); 22 | level::level_enum level() const; 23 | bool should_log(level::level_enum msg_level) const; 24 | 25 | protected: 26 | // sink log level - default is all 27 | level_t level_{level::trace}; 28 | }; 29 | 30 | } // namespace sinks 31 | } // namespace spdlog 32 | 33 | #ifdef SPDLOG_HEADER_ONLY 34 | # include "sink-inl.h" 35 | #endif 36 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/stdout_color_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | template 16 | SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode) 17 | { 18 | return Factory::template create(logger_name, mode); 19 | } 20 | 21 | template 22 | SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode) 23 | { 24 | return Factory::template create(logger_name, mode); 25 | } 26 | 27 | template 28 | SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode) 29 | { 30 | return Factory::template create(logger_name, mode); 31 | } 32 | 33 | template 34 | SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode) 35 | { 36 | return Factory::template create(logger_name, mode); 37 | } 38 | } // namespace spdlog 39 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/stdout_color_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifdef _WIN32 7 | # include 8 | #else 9 | # include 10 | #endif 11 | 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | #ifdef _WIN32 17 | using stdout_color_sink_mt = wincolor_stdout_sink_mt; 18 | using stdout_color_sink_st = wincolor_stdout_sink_st; 19 | using stderr_color_sink_mt = wincolor_stderr_sink_mt; 20 | using stderr_color_sink_st = wincolor_stderr_sink_st; 21 | #else 22 | using stdout_color_sink_mt = ansicolor_stdout_sink_mt; 23 | using stdout_color_sink_st = ansicolor_stdout_sink_st; 24 | using stderr_color_sink_mt = ansicolor_stderr_sink_mt; 25 | using stderr_color_sink_st = ansicolor_stderr_sink_st; 26 | #endif 27 | } // namespace sinks 28 | 29 | template 30 | std::shared_ptr stdout_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 31 | 32 | template 33 | std::shared_ptr stdout_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 34 | 35 | template 36 | std::shared_ptr stderr_color_mt(const std::string &logger_name, color_mode mode = color_mode::automatic); 37 | 38 | template 39 | std::shared_ptr stderr_color_st(const std::string &logger_name, color_mode mode = color_mode::automatic); 40 | 41 | } // namespace spdlog 42 | 43 | #ifdef SPDLOG_HEADER_ONLY 44 | # include "stdout_color_sinks-inl.h" 45 | #endif 46 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/stdout_sinks-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef _WIN32 15 | // under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675) 16 | // so instead we use ::FileWrite 17 | # include 18 | 19 | # ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp 20 | # include // WriteFile (..) 21 | # endif 22 | 23 | # include // _get_osfhandle(..) 24 | # include // _fileno(..) 25 | #endif // WIN32 26 | 27 | namespace spdlog { 28 | 29 | namespace sinks { 30 | 31 | template 32 | SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) 33 | : mutex_(ConsoleMutex::mutex()) 34 | , file_(file) 35 | , formatter_(details::make_unique()) 36 | { 37 | #ifdef _WIN32 38 | // get windows handle from the FILE* object 39 | 40 | handle_ = reinterpret_cast(::_get_osfhandle(::_fileno(file_))); 41 | 42 | // don't throw to support cases where no console is attached, 43 | // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). 44 | // throw only if non stdout/stderr target is requested (probably regular file and not console). 45 | if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) 46 | { 47 | throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); 48 | } 49 | #endif // WIN32 50 | } 51 | 52 | template 53 | SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) 54 | { 55 | #ifdef _WIN32 56 | if (handle_ == INVALID_HANDLE_VALUE) 57 | { 58 | return; 59 | } 60 | std::lock_guard lock(mutex_); 61 | memory_buf_t formatted; 62 | formatter_->format(msg, formatted); 63 | ::fflush(file_); // flush in case there is something in this file_ already 64 | auto size = static_cast(formatted.size()); 65 | DWORD bytes_written = 0; 66 | bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; 67 | if (!ok) 68 | { 69 | throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + std::to_string(::GetLastError())); 70 | } 71 | #else 72 | std::lock_guard lock(mutex_); 73 | memory_buf_t formatted; 74 | formatter_->format(msg, formatted); 75 | ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); 76 | ::fflush(file_); // flush every line to terminal 77 | #endif // WIN32 78 | } 79 | 80 | template 81 | SPDLOG_INLINE void stdout_sink_base::flush() 82 | { 83 | std::lock_guard lock(mutex_); 84 | fflush(file_); 85 | } 86 | 87 | template 88 | SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) 89 | { 90 | std::lock_guard lock(mutex_); 91 | formatter_ = std::unique_ptr(new pattern_formatter(pattern)); 92 | } 93 | 94 | template 95 | SPDLOG_INLINE void stdout_sink_base::set_formatter(std::unique_ptr sink_formatter) 96 | { 97 | std::lock_guard lock(mutex_); 98 | formatter_ = std::move(sink_formatter); 99 | } 100 | 101 | // stdout sink 102 | template 103 | SPDLOG_INLINE stdout_sink::stdout_sink() 104 | : stdout_sink_base(stdout) 105 | {} 106 | 107 | // stderr sink 108 | template 109 | SPDLOG_INLINE stderr_sink::stderr_sink() 110 | : stdout_sink_base(stderr) 111 | {} 112 | 113 | } // namespace sinks 114 | 115 | // factory methods 116 | template 117 | SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) 118 | { 119 | return Factory::template create(logger_name); 120 | } 121 | 122 | template 123 | SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) 124 | { 125 | return Factory::template create(logger_name); 126 | } 127 | 128 | template 129 | SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) 130 | { 131 | return Factory::template create(logger_name); 132 | } 133 | 134 | template 135 | SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) 136 | { 137 | return Factory::template create(logger_name); 138 | } 139 | } // namespace spdlog 140 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/stdout_sinks.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _WIN32 12 | # include 13 | #endif 14 | 15 | namespace spdlog { 16 | 17 | namespace sinks { 18 | 19 | template 20 | class stdout_sink_base : public sink 21 | { 22 | public: 23 | using mutex_t = typename ConsoleMutex::mutex_t; 24 | explicit stdout_sink_base(FILE *file); 25 | ~stdout_sink_base() override = default; 26 | 27 | stdout_sink_base(const stdout_sink_base &other) = delete; 28 | stdout_sink_base(stdout_sink_base &&other) = delete; 29 | 30 | stdout_sink_base &operator=(const stdout_sink_base &other) = delete; 31 | stdout_sink_base &operator=(stdout_sink_base &&other) = delete; 32 | 33 | void log(const details::log_msg &msg) override; 34 | void flush() override; 35 | void set_pattern(const std::string &pattern) override; 36 | 37 | void set_formatter(std::unique_ptr sink_formatter) override; 38 | 39 | protected: 40 | mutex_t &mutex_; 41 | FILE *file_; 42 | std::unique_ptr formatter_; 43 | #ifdef _WIN32 44 | HANDLE handle_; 45 | #endif // WIN32 46 | }; 47 | 48 | template 49 | class stdout_sink : public stdout_sink_base 50 | { 51 | public: 52 | stdout_sink(); 53 | }; 54 | 55 | template 56 | class stderr_sink : public stdout_sink_base 57 | { 58 | public: 59 | stderr_sink(); 60 | }; 61 | 62 | using stdout_sink_mt = stdout_sink; 63 | using stdout_sink_st = stdout_sink; 64 | 65 | using stderr_sink_mt = stderr_sink; 66 | using stderr_sink_st = stderr_sink; 67 | 68 | } // namespace sinks 69 | 70 | // factory methods 71 | template 72 | std::shared_ptr stdout_logger_mt(const std::string &logger_name); 73 | 74 | template 75 | std::shared_ptr stdout_logger_st(const std::string &logger_name); 76 | 77 | template 78 | std::shared_ptr stderr_logger_mt(const std::string &logger_name); 79 | 80 | template 81 | std::shared_ptr stderr_logger_st(const std::string &logger_name); 82 | 83 | } // namespace spdlog 84 | 85 | #ifdef SPDLOG_HEADER_ONLY 86 | # include "stdout_sinks-inl.h" 87 | #endif 88 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/syslog_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | /** 17 | * Sink that write to syslog using the `syscall()` library call. 18 | */ 19 | template 20 | class syslog_sink : public base_sink 21 | { 22 | 23 | public: 24 | syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) 25 | : enable_formatting_{enable_formatting} 26 | , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, 27 | /* spdlog::level::debug */ LOG_DEBUG, 28 | /* spdlog::level::info */ LOG_INFO, 29 | /* spdlog::level::warn */ LOG_WARNING, 30 | /* spdlog::level::err */ LOG_ERR, 31 | /* spdlog::level::critical */ LOG_CRIT, 32 | /* spdlog::level::off */ LOG_INFO}} 33 | , ident_{std::move(ident)} 34 | { 35 | // set ident to be program name if empty 36 | ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); 37 | } 38 | 39 | ~syslog_sink() override 40 | { 41 | ::closelog(); 42 | } 43 | 44 | syslog_sink(const syslog_sink &) = delete; 45 | syslog_sink &operator=(const syslog_sink &) = delete; 46 | 47 | protected: 48 | void sink_it_(const details::log_msg &msg) override 49 | { 50 | string_view_t payload; 51 | memory_buf_t formatted; 52 | if (enable_formatting_) 53 | { 54 | base_sink::formatter_->format(msg, formatted); 55 | payload = string_view_t(formatted.data(), formatted.size()); 56 | } 57 | else 58 | { 59 | payload = msg.payload; 60 | } 61 | 62 | size_t length = payload.size(); 63 | // limit to max int 64 | if (length > static_cast(std::numeric_limits::max())) 65 | { 66 | length = static_cast(std::numeric_limits::max()); 67 | } 68 | 69 | ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast(length), payload.data()); 70 | } 71 | 72 | void flush_() override {} 73 | bool enable_formatting_ = false; 74 | 75 | private: 76 | using levels_array = std::array; 77 | levels_array syslog_levels_; 78 | // must store the ident because the man says openlog might use the pointer as 79 | // is and not a string copy 80 | const std::string ident_; 81 | 82 | // 83 | // Simply maps spdlog's log level to syslog priority level. 84 | // 85 | int syslog_prio_from_level(const details::log_msg &msg) const 86 | { 87 | return syslog_levels_.at(static_cast(msg.level)); 88 | } 89 | }; 90 | 91 | using syslog_sink_mt = syslog_sink; 92 | using syslog_sink_st = syslog_sink; 93 | } // namespace sinks 94 | 95 | // Create and register a syslog logger 96 | template 97 | inline std::shared_ptr syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, 98 | int syslog_facility = LOG_USER, bool enable_formatting = false) 99 | { 100 | return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); 101 | } 102 | 103 | template 104 | inline std::shared_ptr syslog_logger_st(const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, 105 | int syslog_facility = LOG_USER, bool enable_formatting = false) 106 | { 107 | return Factory::template create(logger_name, syslog_ident, syslog_option, syslog_facility, enable_formatting); 108 | } 109 | } // namespace spdlog 110 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/systemd_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #ifndef SD_JOURNAL_SUPPRESS_LOCATION 12 | # define SD_JOURNAL_SUPPRESS_LOCATION 13 | #endif 14 | #include 15 | 16 | namespace spdlog { 17 | namespace sinks { 18 | 19 | /** 20 | * Sink that write to systemd journal using the `sd_journal_send()` library call. 21 | */ 22 | template 23 | class systemd_sink : public base_sink 24 | { 25 | public: 26 | systemd_sink(std::string ident = "", bool enable_formatting = false) 27 | : ident_{std::move(ident)} 28 | , enable_formatting_{enable_formatting} 29 | , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, 30 | /* spdlog::level::debug */ LOG_DEBUG, 31 | /* spdlog::level::info */ LOG_INFO, 32 | /* spdlog::level::warn */ LOG_WARNING, 33 | /* spdlog::level::err */ LOG_ERR, 34 | /* spdlog::level::critical */ LOG_CRIT, 35 | /* spdlog::level::off */ LOG_INFO}} 36 | {} 37 | 38 | ~systemd_sink() override {} 39 | 40 | systemd_sink(const systemd_sink &) = delete; 41 | systemd_sink &operator=(const systemd_sink &) = delete; 42 | 43 | protected: 44 | const std::string ident_; 45 | bool enable_formatting_ = false; 46 | using levels_array = std::array; 47 | levels_array syslog_levels_; 48 | 49 | void sink_it_(const details::log_msg &msg) override 50 | { 51 | int err; 52 | string_view_t payload; 53 | memory_buf_t formatted; 54 | if (enable_formatting_) 55 | { 56 | base_sink::formatter_->format(msg, formatted); 57 | payload = string_view_t(formatted.data(), formatted.size()); 58 | } 59 | else 60 | { 61 | payload = msg.payload; 62 | } 63 | 64 | size_t length = payload.size(); 65 | // limit to max int 66 | if (length > static_cast(std::numeric_limits::max())) 67 | { 68 | length = static_cast(std::numeric_limits::max()); 69 | } 70 | 71 | const string_view_t syslog_identifier = ident_.empty() ? msg.logger_name : ident_; 72 | 73 | // Do not send source location if not available 74 | if (msg.source.empty()) 75 | { 76 | // Note: function call inside '()' to avoid macro expansion 77 | err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), 78 | "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), nullptr); 79 | } 80 | else 81 | { 82 | err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), 83 | "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", 84 | msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); 85 | } 86 | 87 | if (err) 88 | { 89 | throw_spdlog_ex("Failed writing to systemd", errno); 90 | } 91 | } 92 | 93 | int syslog_level(level::level_enum l) 94 | { 95 | return syslog_levels_.at(static_cast(l)); 96 | } 97 | 98 | void flush_() override {} 99 | }; 100 | 101 | using systemd_sink_mt = systemd_sink; 102 | using systemd_sink_st = systemd_sink; 103 | } // namespace sinks 104 | 105 | // Create and register a syslog logger 106 | template 107 | inline std::shared_ptr systemd_logger_mt( 108 | const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) 109 | { 110 | return Factory::template create(logger_name, ident, enable_formatting); 111 | } 112 | 113 | template 114 | inline std::shared_ptr systemd_logger_st( 115 | const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) 116 | { 117 | return Factory::template create(logger_name, ident, enable_formatting); 118 | } 119 | } // namespace spdlog 120 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/tcp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | # include 11 | #else 12 | # include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #pragma once 21 | 22 | // Simple tcp client sink 23 | // Connects to remote address and send the formatted log. 24 | // Will attempt to reconnect if connection drops. 25 | // If more complicated behaviour is needed (i.e get responses), you can inherit it and override the sink_it_ method. 26 | 27 | namespace spdlog { 28 | namespace sinks { 29 | 30 | struct tcp_sink_config 31 | { 32 | std::string server_host; 33 | int server_port; 34 | bool lazy_connect = false; // if true connect on first log call instead of on construction 35 | 36 | tcp_sink_config(std::string host, int port) 37 | : server_host{std::move(host)} 38 | , server_port{port} 39 | {} 40 | }; 41 | 42 | template 43 | class tcp_sink : public spdlog::sinks::base_sink 44 | { 45 | public: 46 | // connect to tcp host/port or throw if failed 47 | // host can be hostname or ip address 48 | 49 | explicit tcp_sink(tcp_sink_config sink_config) 50 | : config_{std::move(sink_config)} 51 | { 52 | if (!config_.lazy_connect) 53 | { 54 | this->client_.connect(config_.server_host, config_.server_port); 55 | } 56 | } 57 | 58 | ~tcp_sink() override = default; 59 | 60 | protected: 61 | void sink_it_(const spdlog::details::log_msg &msg) override 62 | { 63 | spdlog::memory_buf_t formatted; 64 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 65 | if (!client_.is_connected()) 66 | { 67 | client_.connect(config_.server_host, config_.server_port); 68 | } 69 | client_.send(formatted.data(), formatted.size()); 70 | } 71 | 72 | void flush_() override {} 73 | tcp_sink_config config_; 74 | details::tcp_client client_; 75 | }; 76 | 77 | using tcp_sink_mt = tcp_sink; 78 | using tcp_sink_st = tcp_sink; 79 | 80 | } // namespace sinks 81 | } // namespace spdlog 82 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/udp_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #ifdef _WIN32 10 | # include 11 | #else 12 | # include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // Simple udp client sink 21 | // Sends formatted log via udp 22 | 23 | namespace spdlog { 24 | namespace sinks { 25 | 26 | struct udp_sink_config 27 | { 28 | std::string server_host; 29 | uint16_t server_port; 30 | 31 | udp_sink_config(std::string host, uint16_t port) 32 | : server_host{std::move(host)} 33 | , server_port{port} 34 | {} 35 | }; 36 | 37 | template 38 | class udp_sink : public spdlog::sinks::base_sink 39 | { 40 | public: 41 | // host can be hostname or ip address 42 | explicit udp_sink(udp_sink_config sink_config) 43 | : client_{sink_config.server_host, sink_config.server_port} 44 | {} 45 | 46 | ~udp_sink() override = default; 47 | 48 | protected: 49 | void sink_it_(const spdlog::details::log_msg &msg) override 50 | { 51 | spdlog::memory_buf_t formatted; 52 | spdlog::sinks::base_sink::formatter_->format(msg, formatted); 53 | client_.send(formatted.data(), formatted.size()); 54 | } 55 | 56 | void flush_() override {} 57 | details::udp_client client_; 58 | }; 59 | 60 | using udp_sink_mt = udp_sink; 61 | using udp_sink_st = udp_sink; 62 | 63 | } // namespace sinks 64 | 65 | // 66 | // factory functions 67 | // 68 | template 69 | inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) 70 | { 71 | return Factory::template create(logger_name, skin_config); 72 | } 73 | 74 | } // namespace spdlog 75 | -------------------------------------------------------------------------------- /thirdpart/spdlog/sinks/wincolor_sink.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace spdlog { 18 | namespace sinks { 19 | /* 20 | * Windows color console sink. Uses WriteConsoleA to write to the console with 21 | * colors 22 | */ 23 | template 24 | class wincolor_sink : public sink 25 | { 26 | public: 27 | wincolor_sink(void *out_handle, color_mode mode); 28 | ~wincolor_sink() override; 29 | 30 | wincolor_sink(const wincolor_sink &other) = delete; 31 | wincolor_sink &operator=(const wincolor_sink &other) = delete; 32 | 33 | // change the color for the given level 34 | void set_color(level::level_enum level, std::uint16_t color); 35 | void log(const details::log_msg &msg) final override; 36 | void flush() final override; 37 | void set_pattern(const std::string &pattern) override final; 38 | void set_formatter(std::unique_ptr sink_formatter) override final; 39 | void set_color_mode(color_mode mode); 40 | 41 | protected: 42 | using mutex_t = typename ConsoleMutex::mutex_t; 43 | void *out_handle_; 44 | mutex_t &mutex_; 45 | bool should_do_colors_; 46 | std::unique_ptr formatter_; 47 | std::array colors_; 48 | 49 | // set foreground color and return the orig console attributes (for resetting later) 50 | std::uint16_t set_foreground_color_(std::uint16_t attribs); 51 | 52 | // print a range of formatted message to console 53 | void print_range_(const memory_buf_t &formatted, size_t start, size_t end); 54 | 55 | // in case we are redirected to file (not in console mode) 56 | void write_to_file_(const memory_buf_t &formatted); 57 | 58 | void set_color_mode_impl(color_mode mode); 59 | }; 60 | 61 | template 62 | class wincolor_stdout_sink : public wincolor_sink 63 | { 64 | public: 65 | explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); 66 | }; 67 | 68 | template 69 | class wincolor_stderr_sink : public wincolor_sink 70 | { 71 | public: 72 | explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); 73 | }; 74 | 75 | using wincolor_stdout_sink_mt = wincolor_stdout_sink; 76 | using wincolor_stdout_sink_st = wincolor_stdout_sink; 77 | 78 | using wincolor_stderr_sink_mt = wincolor_stderr_sink; 79 | using wincolor_stderr_sink_st = wincolor_stderr_sink; 80 | } // namespace sinks 81 | } // namespace spdlog 82 | 83 | #ifdef SPDLOG_HEADER_ONLY 84 | # include "wincolor_sink-inl.h" 85 | #endif 86 | -------------------------------------------------------------------------------- /thirdpart/spdlog/spdlog-inl.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #ifndef SPDLOG_HEADER_ONLY 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | namespace spdlog { 14 | 15 | SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) 16 | { 17 | details::registry::instance().initialize_logger(std::move(logger)); 18 | } 19 | 20 | SPDLOG_INLINE std::shared_ptr get(const std::string &name) 21 | { 22 | return details::registry::instance().get(name); 23 | } 24 | 25 | SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) 26 | { 27 | details::registry::instance().set_formatter(std::move(formatter)); 28 | } 29 | 30 | SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) 31 | { 32 | set_formatter(std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); 33 | } 34 | 35 | SPDLOG_INLINE void enable_backtrace(size_t n_messages) 36 | { 37 | details::registry::instance().enable_backtrace(n_messages); 38 | } 39 | 40 | SPDLOG_INLINE void disable_backtrace() 41 | { 42 | details::registry::instance().disable_backtrace(); 43 | } 44 | 45 | SPDLOG_INLINE void dump_backtrace() 46 | { 47 | default_logger_raw()->dump_backtrace(); 48 | } 49 | 50 | SPDLOG_INLINE level::level_enum get_level() 51 | { 52 | return default_logger_raw()->level(); 53 | } 54 | 55 | SPDLOG_INLINE bool should_log(level::level_enum log_level) 56 | { 57 | return default_logger_raw()->should_log(log_level); 58 | } 59 | 60 | SPDLOG_INLINE void set_level(level::level_enum log_level) 61 | { 62 | details::registry::instance().set_level(log_level); 63 | } 64 | 65 | SPDLOG_INLINE void flush_on(level::level_enum log_level) 66 | { 67 | details::registry::instance().flush_on(log_level); 68 | } 69 | 70 | SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) 71 | { 72 | details::registry::instance().set_error_handler(handler); 73 | } 74 | 75 | SPDLOG_INLINE void register_logger(std::shared_ptr logger) 76 | { 77 | details::registry::instance().register_logger(std::move(logger)); 78 | } 79 | 80 | SPDLOG_INLINE void apply_all(const std::function)> &fun) 81 | { 82 | details::registry::instance().apply_all(fun); 83 | } 84 | 85 | SPDLOG_INLINE void drop(const std::string &name) 86 | { 87 | details::registry::instance().drop(name); 88 | } 89 | 90 | SPDLOG_INLINE void drop_all() 91 | { 92 | details::registry::instance().drop_all(); 93 | } 94 | 95 | SPDLOG_INLINE void shutdown() 96 | { 97 | details::registry::instance().shutdown(); 98 | } 99 | 100 | SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) 101 | { 102 | details::registry::instance().set_automatic_registration(automatic_registration); 103 | } 104 | 105 | SPDLOG_INLINE std::shared_ptr default_logger() 106 | { 107 | return details::registry::instance().default_logger(); 108 | } 109 | 110 | SPDLOG_INLINE spdlog::logger *default_logger_raw() 111 | { 112 | return details::registry::instance().get_default_raw(); 113 | } 114 | 115 | SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) 116 | { 117 | details::registry::instance().set_default_logger(std::move(default_logger)); 118 | } 119 | 120 | } // namespace spdlog 121 | -------------------------------------------------------------------------------- /thirdpart/spdlog/stopwatch.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | // Stopwatch support for spdlog (using std::chrono::steady_clock). 10 | // Displays elapsed seconds since construction as double. 11 | // 12 | // Usage: 13 | // 14 | // spdlog::stopwatch sw; 15 | // ... 16 | // spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" 17 | // spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" 18 | // 19 | // 20 | // If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use "duration_cast<..>(sw.elapsed())": 21 | // 22 | // #include 23 | //.. 24 | // using std::chrono::duration_cast; 25 | // using std::chrono::milliseconds; 26 | // spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" 27 | 28 | namespace spdlog { 29 | class stopwatch 30 | { 31 | using clock = std::chrono::steady_clock; 32 | std::chrono::time_point start_tp_; 33 | 34 | public: 35 | stopwatch() 36 | : start_tp_{clock::now()} 37 | {} 38 | 39 | std::chrono::duration elapsed() const 40 | { 41 | return std::chrono::duration(clock::now() - start_tp_); 42 | } 43 | 44 | void reset() 45 | { 46 | start_tp_ = clock::now(); 47 | } 48 | }; 49 | } // namespace spdlog 50 | 51 | // Support for fmt formatting (e.g. "{:012.9}" or just "{}") 52 | namespace 53 | #ifdef SPDLOG_USE_STD_FORMAT 54 | std 55 | #else 56 | fmt 57 | #endif 58 | { 59 | 60 | template<> 61 | struct formatter : formatter 62 | { 63 | template 64 | auto format(const spdlog::stopwatch &sw, FormatContext &ctx) -> decltype(ctx.out()) 65 | { 66 | return formatter::format(sw.elapsed().count(), ctx); 67 | } 68 | }; 69 | } // namespace std 70 | -------------------------------------------------------------------------------- /thirdpart/spdlog/version.h: -------------------------------------------------------------------------------- 1 | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. 2 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 3 | 4 | #pragma once 5 | 6 | #define SPDLOG_VER_MAJOR 1 7 | #define SPDLOG_VER_MINOR 10 8 | #define SPDLOG_VER_PATCH 0 9 | 10 | #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) 11 | -------------------------------------------------------------------------------- /unbind_all_network_card.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | 4 | 5 | output1=$(/home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --status | awk ' 6 | /Network devices using DPDK-compatible driver/ { 7 | getline 8 | while ($0 !~ /^$/) { 9 | if ($0 ~ /^([^ ]+)/) { 10 | device = $1 11 | } 12 | if ($0 ~ /unused=([^ ]+)/) { 13 | unused = substr($0, index($0, "unused=") + 7) 14 | } 15 | if (device && unused) { 16 | print device, unused 17 | } 18 | getline 19 | } 20 | } 21 | ') 22 | 23 | output2=$(/home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --status | awk ' 24 | /Other Network devices/ { 25 | getline 26 | while ($0 !~ /^$/) { 27 | if ($0 ~ /^([^ ]+)/) { 28 | device = $1 29 | } 30 | if ($0 ~ /unused=([^ ]+)/) { 31 | split(substr($0, index($0, "unused=") + 7), arr, ",") 32 | unused = arr[1] 33 | } 34 | if (device && unused) { 35 | print device, unused 36 | } 37 | getline 38 | } 39 | } 40 | ') 41 | 42 | IFS=$'\n' # 设置换行符为字段分隔符 43 | 44 | for line in $output1; do 45 | device=$(echo "$line" | awk '{print $1}') 46 | unused=$(echo "$line" | awk '{print $2}') 47 | /home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --bind="$unused" "$device" 48 | done 49 | 50 | for line in $output2; do 51 | device=$(echo "$line" | awk '{print $1}') 52 | unused=$(echo "$line" | awk '{print $2}') 53 | /home/dpdk/dpdk-stable-21.11.2/usertools/dpdk-devbind.py --bind="$unused" "$device" 54 | done 55 | 56 | rmmod igb_uio --------------------------------------------------------------------------------