You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python Windows Service日志功能失效问题排查求助

问题分析与解决

首先得给你点明一个核心关键点:你在命令行执行install/start/restart/remove这些命令时,运行的Python进程和Windows实际启动的服务进程是完全独立的两个进程

你现在看到的日志(Class openedCalling Handle Command Line),全都是来自你手动在命令行执行脚本的那个进程;而服务真正运行时的进程,是由Windows服务控制管理器(SCM)启动的——它的默认工作目录是C:\Windows\System32,运行账户通常是Local System,这就是你的内部函数日志没出现在预期文件里的根本原因:

  1. 你在代码里重复调用logging.basicConfig,但这个函数只有第一次调用会生效,后续调用都会被忽略。更关键的是,服务进程启动时的工作目录不是你的脚本目录,所以search_server.log会被创建在C:\Windows\System32里,而非你脚本所在的C:\PythonScripts\SearchServer,你自然看不到这些日志。
  2. Local System账户可能没有你脚本目录的写入权限,就算服务进程想往那里写日志也会静默失败。

修复步骤

1. 统一配置日志,使用绝对路径

把日志配置移到脚本最开头,只配置一次,并且指定绝对路径,确保服务进程能精准找到并写入目标文件:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import logging
import os

# 获取脚本所在的绝对路径,彻底规避服务进程工作目录问题
script_dir = os.path.dirname(os.path.abspath(__file__))
log_path = os.path.join(script_dir, 'search_server.log')

# 仅配置一次日志,添加时间戳更便于排查问题
logging.basicConfig(
    filename=log_path,
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class AppServerSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"
    _svc_description_ = "New Test Service"

    def __init__(self, args):
        logging.info('Init function called')
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        logging.info('Stop function called')
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        logging.info('Run function called')
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_, ''))
        self.main()

    def main(self):
        logging.info('Main function called')  # 替换print,服务没有控制台输出,print内容会丢失

if __name__ == '__main__':
    logging.info('Calling Handle Command Line')
    win32serviceutil.HandleCommandLine(AppServerSvc)

2. 确保服务有日志目录的写入权限

如果修改后还是看不到日志,大概率是权限问题,你可以任选一种方式解决:

  • 手动给C:\PythonScripts\SearchServer目录添加Local System账户的写入权限;
  • 把日志路径改到系统默认有写入权限的位置,比如C:\Temp\search_server.log
  • 安装服务时指定有权限的运行账户:python servicetest.py install --username "你的Windows用户名" --password "你的账户密码"

3. 验证之前的问题残留

你可以去C:\Windows\System32目录下找找有没有search_server.log文件,里面应该有服务进程之前生成的InitRunMain这些日志——这就能实锤之前的问题确实是工作目录导致的。

额外提示

  • 服务进程没有控制台窗口,所以print语句的输出你完全看不到,全部换成logging才是正确的调试方式;
  • 不要在类定义里直接写logging.info('Class opened'),因为每次加载类的时候都会执行(包括命令行进程加载类的场景),这就是你看到多次Class opened的原因,建议把这行删掉,只保留业务相关的日志。

内容的提问来源于stack exchange,提问作者Matthew Baker

火山引擎 最新活动