如何让Loguru在NSSM托管的Windows服务Python程序中正常工作?
Loguru文件日志在NSSM Windows服务中失效,且捕获的stdout含多余字符
问题现象
- Python程序通过NSSM注册为Windows服务后,仅NSSM捕获的stdout日志生效,Loguru配置的TRACE级独立文件日志无法生成或写入;但直接在控制台运行程序时,Loguru可同时正常输出到文件和控制台。
- NSSM捕获的stdout日志混入大量ANSI控制字符,可读性极差,示例日志:
[32m08:43:28[0m [1mINFO[0m [1mLogix write [36mInput_From_Word1[0m[1m [32m0[0m[1m & [36mErsa_Input_From_Word2[0m[1m [32m8[0m[1m successful[0m [32m08:43:28[0m [1mINFO[0m [1mLogix tags [36mOutput_To_Word1[0m[1m and [36mRecipe_STRING[0m[1m unchanged [32m08:43:28[0m[1m INFO Skipping Click set([36mDS101[0m[1m,[36mDS300[0m[1m) to [32m0[0m[1m and [32m0844520[0m[1m[0m [32m08:43:39[0m [1mINFO[0m [1mRead Logix tags [36mOutput_To_Word1[0m[1m[0m
当前Loguru配置
logger.remove() # Setup the debug log file logger.add(sink="file_{time}.log", format="{time:HH:mm:ss} {level} {message}", level="TRACE", rotation="25 MB", backtrace=True, diagnose=True, retention="7 days") # Setup the debug to console logger.add(sink=sys.stdout, colorize=True, format="<green>{time:HH:mm:ss}</green> <level>{level}</level> <level>{message}</level>", level="INFO") # So we can have more colors in console window logger = logger.opt(colors=True)
已尝试的无效方案
- 将Loguru文件输出sink改为
open("file_{time}.log", 'rw'),问题依旧 - 修改NSSM服务账户为有权限的特定账户,服务无法启动;尝试将程序放在Public目录,服务也无法启动,目前保留在注册账户的目录下
需求
- 实现Loguru的TRACE级独立文件日志在Windows服务中正常工作
- 或让NSSM捕获的stdout日志不再包含多余控制字符
解决方法
一、修复Loguru文件日志失效问题
- 使用绝对路径指定日志文件
服务运行时的工作目录通常不是程序所在目录,导致相对路径无法找到正确位置。修改日志文件路径为绝对路径:
import os logger.add( sink=os.path.join(os.path.dirname(os.path.abspath(__file__)), "file_{time}.log"), format="{time:HH:mm:ss} {level} {message}", level="TRACE", rotation="25 MB", backtrace=True, diagnose=True, retention="7 days" )
- 确保服务账户有日志目录读写权限
- 若使用
LocalSystem账户,默认对系统级目录权限充足,可将日志放在C:\ProgramData\你的程序名\logs这类目录,提前创建并赋予LocalSystem读写权限 - 若使用自定义账户,确保该账户对程序目录及日志目录有完全控制权限
- 不要手动打开文件句柄
Loguru的sink直接传入文件名时,会自动处理文件创建、轮转、权限等逻辑;手动用open()会破坏这些机制,且可能因服务环境下的文件句柄问题导致写入失败,因此必须改回直接传文件名的方式
二、清除stdout日志中的多余控制字符
- 根据运行环境动态关闭颜色输出
服务运行时无交互式终端,无需颜色输出,可通过sys.stdout.isatty()判断环境,动态关闭颜色:
import sys is_service = not sys.stdout.isatty() logger.add( sink=sys.stdout, colorize=not is_service, format="{time:HH:mm:ss} {level} {message}" if is_service else "<green>{time:HH:mm:ss}</green> <level>{level}</level> <level>{message}</level>", level="INFO" )
- 移除全局颜色优化
若不需要全局颜色支持,可删除logger = logger.opt(colors=True),避免额外的ANSI字符输出
内容的提问来源于stack exchange,提问作者blownupp
相关产品推荐
相关产品推荐

