spdlog 封装为 DLL

2023-05-16

项目中需要快速写入巨量日志,一开始用的是boost::log,但遇到崩溃问题,程序负载大了,滚动日志时偶尔会崩溃,总是报:
boost::filesystem_errorbad_year, bad_month 一些问题。在boost官网,和github上的 boostlog 项目 issue中窥见些端倪,说是boost::filesystem存在问题blabla
枉我还一直很信任 boost ,还是换个日志库吧。

github 上 spdlog 星星比 boost::log 多多了,boost::log 好像用的人挺少。

这一换发现:相比boost::log,spdlog 速度又快,占内存又小(取决于队列长度)

使用 spdlog1.10.0 封装的 dll

  • 使用这个dll,你的项目不用再依赖 spdlog 头文件
  • C 风格的字符串格式化语法
  • 同步/异步、滚动日志
  • 程序退出前需要调用静态方法 shutdown()
  • VS2019 编译通过
    在这里插入图片描述
// log_spd.h
#pragma once
#include <string>
#ifndef LOG_LIB_H
#define LOG_LIB_H

#ifdef _MSC_VER
#define LOG_API _declspec(dllexport)
#else
#define LOG_API 
#endif

class SpdlogWrapper;

enum class lv {
    trace,
    debug,
    info,
    warn,
    error,
    fatal
};

class LOG_API Logger
{
public:
    Logger();
    Logger(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);
    Logger(const Logger&);
    Logger& operator=(const Logger&);
    ~Logger();

    // 返回一个日志对象
    static Logger createLogger(const std::string& filename, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);

    // 全局设置。定时写日志到文件。0 秒则不启用
    static void setFlushEverySec(int sec);

    // 设置日志文件
    void setFileName(const std::string&);

    // 设置日志前缀格式;default: [%Y-%m-%d %H:%M:%S.%e][%t][%l] %v
    void setFormat(const std::string&);

    // 设置日志等级,大于此等级才写入文件
    void setLevel(lv);

    // 设置滚动日志文件
    void setRotateFile(int size /* MB */, int count);

    // 设置立即写到文件的日志等级
    void setFlushOnLevel(lv);

    // 是否异步日志,default: true
    void setAsyncMode(bool);

    // 设置异步日志队列长度。默认 256。经测试,队列更长,占用内存更大,未见性能明显提升
    void setAsyncQueueSize(int);

    // 在调用 setXX 类函数之后,最后调用 init(); 赋值操作后,被赋值的对象需要重新 init()
    void init();
    void init(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);

    // 格式化后的字符串最大长度: 1024
    void trace(const char* fmt, ...);
    void info(const char* fmt, ...);
    void debug(const char* fmt, ...);
    void warn(const char* fmt, ...);
    void error(const char* fmt, ...);
    void fatal(const char* fmt, ...);

    // 异步模式:通知缓冲, 要求写入日志文件;
    // 同步模式:立即写入日志文件
    void flush();

    // EXE 主程序退出前需要调用。因为 spdlog 在 windows 上存在问题关不掉程序
    // 如果是在 dll 中使用此日志库,你的 dll 需要提供接口来让 EXE 程序在退出前主动调用到此函数
    static void shutdown();

private:
    SpdlogWrapper* m_logWrapper;
};


#endif // LOG_LIB_H

// log_spd.cpp
#pragma once
#include "log_spd.h"
#include "log_wrapper.h"


Logger::Logger() : m_logWrapper(nullptr)
{
    m_logWrapper = new SpdlogWrapper(DEFAULT_FILE, lv::trace, 100, 5);
}

Logger::Logger(const std::string& file,
    lv level,
    int rotateFileSize, // MB
    int rotateFileCount) : m_logWrapper(nullptr)
{
    m_logWrapper = new SpdlogWrapper(file, level, rotateFileSize, rotateFileCount);
}

Logger::Logger(const Logger& logger)
{
    m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);
}

Logger& Logger::operator=(const Logger& logger)
{
    delete m_logWrapper;
    m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);
    return *this;
}

Logger::~Logger()
{
    delete m_logWrapper;
}

void Logger::init()
{
    m_logWrapper->init();
}

void Logger::init(const std::string& file, lv level, int rotateFileSize, int rotateFileCount)
{
    m_logWrapper->m_fileName = file;
    m_logWrapper->m_logLevel = level;
    m_logWrapper->m_fileSize = rotateFileSize;
    m_logWrapper->m_fileCount = rotateFileCount;
    m_logWrapper->init();
}

Logger Logger::createLogger(const std::string& filename, lv level, int rotateFileSize, int rotateFileCount)
{
    return Logger(filename, level, rotateFileSize, rotateFileCount);
}
void Logger::setAsyncMode(bool enabled)
{
    m_logWrapper->m_async = enabled;
}

void Logger::flush()
{
    m_logWrapper->flush();
}

void Logger::setFileName(const std::string& file)
{
    m_logWrapper->m_fileName = file;
}

void Logger::setFormat(const std::string& fmt)
{
    m_logWrapper->m_fmt = fmt;
}

void Logger::setLevel(lv level)
{
    m_logWrapper->m_logLevel = level;
}

void Logger::setFlushOnLevel(lv level)
{
    m_logWrapper->m_flushOnLevel = (int)level;
}

void Logger::setFlushEverySec(int sec)
{
    SpdlogWrapper::FlushEverySec = sec;
}

void Logger::setAsyncQueueSize(int size)
{
    m_logWrapper->m_queueSize = size;
}

void Logger::setRotateFile(int rotateFileSize, int rotateFileCount)
{
    m_logWrapper->m_fileSize = rotateFileSize;
    m_logWrapper->m_fileCount = rotateFileCount;
}

void Logger::shutdown()
{
    SpdlogWrapper::shutdown();
}

void Logger::trace(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::trace)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::trace);
}

void Logger::info(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::info)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::info);
}

void Logger::debug(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::debug)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::debug);
}

void Logger::warn(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::warn)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::warn);
}

void Logger::error(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::error)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::error);
}

void Logger::fatal(const char* fmt, ...)
{
    if (m_logWrapper->m_logLevel > lv::fatal)
        return;

    char buff[BUFF_SIZE];
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
    va_end(ap);
    m_logWrapper->write(buff, lv::fatal);
}
// log_wrapper.h
#pragma once
#ifndef LOG_API_H
#define LOG_API_H
#include <string>
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/details/thread_pool.h"

static const int BUFF_SIZE = 1024;
const std::string DEFAULT_FILE = "log.log";
const std::string DEFAULT_FMT = "[%Y-%m-%d %H:%M:%S.%e][%t][%l] %v";

class SpdlogWrapper
{

public:
    SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount);
    SpdlogWrapper(const SpdlogWrapper&);
    ~SpdlogWrapper();

    void init();
    void write(const char* msg, lv level);
    void flush();

    static void shutdown();

    static int FlushEverySec;
    static int Id;
    static bool GlobalAttr;

    bool m_async;
    int m_queueSize;
    lv m_logLevel;
    int m_flushOnLevel;
    int m_fileCount;
    int m_fileSize;
    std::string m_fileName;
    std::string m_fmt;

private:
    std::string m_logName;
    std::shared_ptr<spdlog::logger> m_spdLogger;
    std::shared_ptr<spdlog::details::thread_pool> m_tp;
    std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> m_sink;

    void initGlobalAttr();
};
#endif //LOG_API_H

// log_wrapper.cpp
#pragma once
#include "log_spd.h"
#include "log_wrapper.h"


int SpdlogWrapper::Id = 0;
int SpdlogWrapper::FlushEverySec = 3;
bool SpdlogWrapper::GlobalAttr = false;
SpdlogWrapper::SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount)
    : m_fileCount(rotateFileCount), 
    m_fileSize(rotateFileSize), 
    m_logLevel(level), 
    m_fileName(file), 
    m_flushOnLevel(-1),
    m_fmt(DEFAULT_FMT), 
    m_logName(""), 
    m_queueSize(256),
    m_async(true)
{

}

SpdlogWrapper::SpdlogWrapper(const SpdlogWrapper& log)
{
    m_fileCount = log.m_fileCount;
    m_fileSize = log.m_fileSize;
    m_logLevel = log.m_logLevel;
    m_fileName = log.m_fileName;
    m_flushOnLevel = log.m_flushOnLevel;
    m_fmt = log.m_fmt;
    m_logName = "";
    m_queueSize = log.m_queueSize;
    m_async = log.m_async;

    m_spdLogger = nullptr;
    m_tp = nullptr;
    m_sink = nullptr;
}

void SpdlogWrapper::init()
{
    if (m_spdLogger)
        spdlog::drop(m_logName);

    initGlobalAttr();

    m_logName = "__log__" + std::to_string(SpdlogWrapper::Id++);
    if (m_async) {
        m_tp = std::make_shared<spdlog::details::thread_pool>(m_queueSize, 1U);
        m_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(m_fileName, m_fileSize * 1024 * 1024, m_fileCount);
        m_spdLogger = std::make_shared<spdlog::async_logger>(m_logName, m_sink, m_tp, spdlog::async_overflow_policy::block);
        spdlog::register_logger(m_spdLogger);
    }
    else 
        m_spdLogger = spdlog::rotating_logger_mt(m_logName, m_fileName, (size_t)m_fileSize * 1024 * 1024, m_fileCount);

    m_spdLogger->set_pattern(m_fmt);
    m_spdLogger->set_level((spdlog::level::level_enum)m_logLevel);

    if (m_flushOnLevel >= 0)
        m_spdLogger->flush_on((spdlog::level::level_enum)m_flushOnLevel);
}

void SpdlogWrapper::initGlobalAttr()
{
    if (!SpdlogWrapper::GlobalAttr) {
        spdlog::flush_every(std::chrono::seconds(SpdlogWrapper::FlushEverySec));
        SpdlogWrapper::GlobalAttr = true;
    }
}

void SpdlogWrapper::write(const char* msg, lv level)
{
    SPDLOG_LOGGER_CALL(m_spdLogger, (spdlog::level::level_enum)level, msg);
}

void SpdlogWrapper::flush()
{
    if (m_spdLogger)
        m_spdLogger->flush();
}

void SpdlogWrapper::shutdown()
{
    spdlog::drop_all();
    spdlog::shutdown();
}

SpdlogWrapper::~SpdlogWrapper()
{
    if (m_spdLogger)
        spdlog::drop(m_logName);
}

使用

// main.cpp

#include "log_spd.h"

int main(int argc, char  *argv[])
{
	Logger logger, logger2;
	// Logger logger = Logger::createLogger("mylog.log", lv::trace, 100, 5);
	logger.setAsyncMode(false); 
	logger.init();
	logger.trace("Hello %s, you are the %dth visitor.", "Tony", 1);
	logger.flush();
	
	logger2 = logger;
	logger2.setAsyncMode(true);
	logger2.setFormat("%+");
	logger2.init("mylog.log");
	logger2.info("blasa bad w");
	logger2.flush();
	
	Logger::shutdown();
	return 0;
}

log.log

[2022-09-30 14:32:25.065][9532][trace] Hello Tony, you are the 1th visitor.

mylog.log

[2022-09-30 14:32:25.069] [__log__1] [info] [log_wrapper.cpp:75] blasa bad woa

缺点

  • 输出日志所在的代码文件、行号不是调用封装接口的行。比如上面的 [log_wrapper.cpp:75]

编译好的库

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spdlog 封装为 DLL 的相关文章

  • Docker学习目录

    自己整理的笔记 1 docker的安装及常用命令 2 docker的commit和容器数据卷 3 docker安装部署一些软件 xff08 nginx tomcat mysql es xff09 4 DockerFile的使用 5 Dock
  • Docker Compose

    1 Docker Compose官网说明 理解 Compose是Docker官方的开源项目 需要安装 xff01 Dockerfile 让程序在任何地方运行 web服务 redis mysql nginx 多个容器 run Compose的
  • Docker Swarm

    1 购买4台阿里云 按量付费买四台 2 都安装docker Xshell右键 可以将命令发送到所有会话 3 查看官网 地址 xff1a https docs docker com engine swarm 4 工作模式 5 搭建集群 私网不
  • 使用GPU跑代码,设置使用哪块GPU

    服务器多张GPU同时跑代码 1 查看电脑的显卡有几块 在控制台输入 nvidia smi 发现服务器有两个显卡 xff0c 0号和1号 2 在代码中指定GPU 使用0号显卡 xff1a device 61 torch span class
  • android StringBuiler常用方法

    String在java中是不可变长的 频繁拼接修改等效率会很低 StringBuiler 是个可变长的 xff0c 处理字符串效率比较高也可以减少内存开支 xff0c 比如append时并不是用String存储 而是放到一个value的ch
  • C++中的迭代器和泛型算法

    简单的迭代器和算法 1 迭代器令算法不依赖于容器 xff0c 但算法依赖于元素类型的操作 泛型算法本身不会执行容器的操作 xff0c 它们只会运行于迭代器之上 xff0c 执行迭代器的操作 算法永远不会改变底层容器的大小 算法可能改变容器中
  • 宝塔面板无法打开

    宝塔面板无法打开 在别的应用软件像putty 宝塔等打不开时 xff0c 弹出以下页面 在阿里云官网搜索服务器 rm f www server panel data admin path pl 到底部执行并保存 再次访问宝塔等就可以了
  • 【Ubuntu 安装指定版本RabbitMQ ※便捷版※】

    Ubuntu 16 04 安装 RabbitMQ 3 7 4 第一步 安装 erlang 需要注意 erlang和rabbitmq的版本比对关系 https www rabbitmq com which erlang html 我这里安装的
  • JavaScript 文件对象详解

    在浏览器中操作文件 xff0c 多数情况下用到的是 File 对象 xff0c 从 lt input type 61 39 file 39 gt 元素获取 xff0c 进而继续操作 例如将选择的图片展示在页面上 xff0c 用ajax将文件
  • 协议栈的定义

    所谓协议栈就是对信息进行多次封装和解封的过程 xff0c 以便能够在不同的实体间传送信息 是根据OSI体系模型划分的各层协议的总和 就是一套协议的规范 xff0c 比如HTTP gt TCP gt IP xff0c 一个HTTP请求 xff
  • 死锁,死锁的四个必要条件以及处理策略

    一 什么是死锁二 死锁与饥饿三 资源的类型 3 1 可重用资源和消耗性资源 3 1 1 可重用资源 xff08 永久性资源 xff09 3 1 2 消耗性资源 xff08 临时性资源 xff09 3 2 可抢占资源和不可抢占资源 3 2 1
  • 排查机器 负载过高, ssh进不去问题

    排查路径 xff1a 1 一开始怀疑可能是io阻塞导致 xff0c 于是使用iostat xdm 1 100 xff0c 查看 io状况 xff0c 发现io不高 2 于是使用top xff0c 查看系统负载情况 发现系统负载很高 xff0
  • 什么是奇偶校验

    什么是奇偶校验 对数据传输正确性的一种校验方法 在数据传输前附加一位奇校验位 xff0c 用来表示传输的数据中 34 1 34 的个数是奇数还是偶数 xff0c 为奇数时 xff0c 校验位置为 34 0 34 xff0c 否则置为 34
  • Linux CentOS 7 elasticsearch 设置开机自启

    在 etc systemd system目录下创建elasticsearch service文件 span class token namespace Unit span Description 61 elasticsearch span
  • Centos7 设置开机自启的几种方式

    一 系统服务的方式 1 前提 xff08 1 xff09 首先要将需要自启的软件或应用注册成系统服务 xff0c 下面提供常用的软件注册系统服务的案例 nginx service 创建服务文件 vi usr lib systemd syst
  • ubuntu18.04 server配置 ip地址

    ubuntu18 04 server xff0c 启用了新的网络工具netplan xff0c 下面对齐配置参数进行介绍 1 其网络配置文件是放在 etc netplan yaml 缺省dhcp打开方式 xff0c 如果要配置静态地址 xf
  • Ardupilot基于UWB的定位飞行测试

    拖了许久的测试视频 xff0c 终于要发布了 xff0c 上个版本的代码有点问题 xff0c 没有考虑清楚UWB和NED坐标系的关系 xff0c 导致后面飞行故障不断 xff0c 这款UWB的坐标系为ENU坐标系 xff0c 飞机飞行的坐标
  • AutoBoat自动导航无人船

    AutoBoat 自动导航支持航线规划无人船 AutoBoat是一款功能强大自动驾驶无人船 xff0c 同时还可以搭配多款地面控制站使用 地面站中可以在线升级固件 调参 xff0c 使用一套全双工的无线数据传输系统在地面站与小车之间建立起一
  • PIXHAWK上安装PX4Flow光流传感器及调试过程

    小编最近刚调试完光流传感器 xff0c 效果非常理想 xff0c 无GPS情况下很稳定 小编把调试过程的过程和遇到的问题分享给大家 xff0c 希望大家少走弯路 在安装和调试光流传感器之前 xff0c 先保证旋翼机已经安装和调试完毕 xff
  • 正点原子STM32学习笔记——MPU6050介绍

    一 MPU6050简介 1 什么是MPU6050 xff1f MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件 xff0c 内带3轴陀螺仪和3轴加速度传感器 xff0c 并且含有一个第二IIC接口 xff0c 可

随机推荐

  • 【OFDM系列4】OFDM信号多径信道模型基础知识

    多径信道模型 Multipath Channel Scenario 信道脉冲响应 Channel Impulse Response CIR 信道的复基带脉冲响应如下所示 h t l 1 L a l
  • LACP负载分担配置

    网络拓扑图如下 交换机3的配置 Huawei int Eth Trunk 1 Huawei Eth Trunk1 mode lacp static xff08 负载分担模式设置为LACP模式 xff09 Huawei Eth Trunk1
  • 在 NVIDIA jetson tx2 上基于 realsense d435i 相机运行 vins 相关配置

    在 NVIDIA jetson tx2 上基于 realsense d435i 相机运行 vins 相关配置 一 tx2刷机二 安装librealsense xff0c realsense驱动1 安装依赖库2 从debian reposit
  • linux串口传感器处理接收不完整,数据丢失问题分析

    简介 因为当前项目需要在一个linux系统下进行串口传感器的收发工作 xff0c 该串口传感器的收发使用的是字节流专有协议 xff0c 按照每一个字节的十六进制编码来确定协议数据 按照以往的思路 xff0c 串口就是最简单的外设的思想 xf
  • STM32与上位机串口通讯的学习笔记(简明的数据帧设计方法)

    最近因为项目需要 xff0c 需要做一个STM32和Windows的串口通讯协议来交换数据 xff0c 本着追求极致的心态 xff0c 来讨论一下简明的数据帧的设计方法 数据的传输方式 对于很多单片机初学者而言 xff0c 可能他们接触到串
  • 通讯协议(modbus协议和serial读取数据)

    通讯协议 1 调试助手1 1 crc计算助手1 2 串口调试助手 2 使用serial节点读取数据3 modbus协议3 1 报文3 2 功能号3 2 1主机对从机写数据操作3 2 2主机对从机读数据操作 3 3 MODBUS报文模型 4
  • Qt5开发(一)使用记录

    Qt使用记录 一 QtCreator 快捷使用方式1 快速切换已打开的文件2 快速添加函数3 修改变量名 并应用到所有使用该变量的地方 4 选中光标所在的单词5 删除光标所在行6 其他快捷键7 QtCreator配置代码自动格式化8 快捷键
  • Windows10系统运行msconfig(系统配置)选择安全引导后,登录账户显示密码错误的一种较为简易的解决方法

    问题背景描述 在Windows10环境下 xff0c 由于前几天下载到一个带有极多捆绑软件的文件 xff08 常在河边走 xff0c 哪有不湿鞋 xff09 xff0c 为了删除一个流氓软件 xff0c 于是根据网上文章提示便运行 msco
  • 学习笔记-MATLAB的函数bwconncomp算法解析

    一 说明 bwconncomp函数的作用是在一个二值图像中找出每一个连通分量 xff0c 并返回一个结构体CC xff0c CC中包含了图像及连通分量的一些属性 笔者使用的MATLAB版本为2018a xff0c 且在该版本中 xff0c
  • PX环境搭建编译px4_fmu-v2_default相关问题的解决方法

    背景说明 笔者在ubuntu18 04下搭建PX环境时git clone的是较新版本的PX4 Autopilot链接在此 xff08 而目前网上的教程基本是较老版本的Firmware xff0c 两者文件分布不相同 xff0c 所以已有的方
  • PX4编译过程中报错通用解决办法

    背景说明 时刻两年 xff0c 再次配置PX4环境 xff0c 又踩了一遍坑 xff0c 过程中遇到报错真的是欲哭无泪 xff0c 但是解决完回头再来看其实问题并不复杂 本篇文章面向在PX4 Autopilot目录执行命令 make px4
  • CMakeList使用总结

    一 cmake功能介绍 cmake是跨平台编译工具 xff0c 编写简单好维护 xff0c 是make的高级用法 1 编写CMakeList txt文件 通过cmake生成Makefile文件 xff0c make生成可执行文件 静态库 共
  • Mavlink任务协议

    联系作者QQ 843230304 本文翻译自 https mavlink io en services mission html mission protocol Mavlink任务协议 任务子协议允许GCS或开发人员API 在无人机 组件
  • QGroundControl增加菜单栏新建窗口

    作者qq 843230304 欢迎交流分享 MainWindow h 这个函数创建内部DockWidget xff08 即小窗口 xff09 bool createInnerDockWidget const QString amp widg
  • QGC 的 px4参数元数据文件(固件插件)

    1 QGC 资源位置 qrc FirmwarePlugin PX4 PX4ParameterFactMetaData xml 2 参数组 xml描述 3 每一个参数组里面包含很多参数 4 单个参数 加载固件参数xml文件 connect v
  • vsCode编译器操作git

    用vsCode编译器操作git 超级方便 1 打开cmd拉取项目 2 打开这个项目看一下 3 用vscode打开这个项目 xff0c 是在master分支 xff0c 所以要先新建自己的分支 4 test分支只是个例子哈 5 创建完 xff
  • [Python] ImportError: DLL load failed ... 找不到指定的模块 此类问题解决方法

    文章目录 问题定位结论补充 问题 最近升级 Python 项目 xff0c 由 Python2 7 升级到 Python3 8 3 xff0c 项目使用了 PySide2 xff0c 对于较新的Python3 8 3 PySide2 可能存
  • SVG工具Inkscape使用记录

    1 Q 网上下载的svg xff0c 使用 Inkscape 编辑 xff0c 修改颜色 gt 保存 xff0c 结果颜色并没有修改 A 用文本编辑器打开svg文件 xff0c 删除 path属性中的 fill 61 属性 xff0c 保存
  • [Python] 将py转为 pyc 来保护源码并不实用

    Python 做为一种解释型语言 xff0c 做为服务端程序还好 但如果做为客户端程序 xff0c 就有了暴露源码的问题 很多开发者在寻求安全 便捷的发布程序的方法 比如用pyinstaller xff0c py2exe xff0c 或者转
  • spdlog 封装为 DLL

    项目中需要快速写入巨量日志 xff0c 一开始用的是boost log xff0c 但遇到崩溃问题 xff0c 程序负载大了 xff0c 滚动日志时偶尔会崩溃 xff0c 总是报 xff1a boost filesystem error x