小能豆

使用 python logger 仅将 stderr 记录到日志文件

py

我已经设置了一个记录器,但我不知道如何仅在命令失败或生成 stderr 时进行记录。

def RunAndLog(self, command, logf)
   p = subprocess.Popen(command, shell=False, 
           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   (stdout, stderr) = p.communicate()
   logger = logging.getLogger('check rel')
   logger.setLevel(logging.ERROR)
   filehand = logging.handlers.RotatingFileHandler(logFile, mode='a',maxBytes=0,
              backupCount=0, encoding=None, delay=0)
   filehand.setLevel(logging.ERROR)
   lformat = logging.Formatter('%(message)s')
   filehand.setFormatter(lformat)
   logger.addHandler(filehand)
   logger.info(stdout)
   logger.error(stderr)
   logger.removeHandler(filehand)

我调用这个来列出目录。例如,

self.RunAndLog(["dir","%s",pathtodir], "test.log")

test.log包含两种情况的消息,即当目录不存在时以及当目录存在时…这是一个例子:

#case where dir doesn't exist
dir: /path/to/dir/dir1: No such file or directory

# case where it does
bin lib include src test python doc

我如何才能test.log仅在目录不存在或dir命令失败且退出状态非零的情况下记录消息?


阅读 20

收藏
2024-12-29

共1个答案

小能豆

要实现只记录命令失败或有 stderr 输出的日志,可以对命令的退出状态码和 stderr 进行检查。在你的代码中,可以根据 subprocess.Popen 的返回值 p.returncodestderr 是否非空,来决定是否记录日志。

以下是改进后的代码:

import subprocess
import logging
from logging.handlers import RotatingFileHandler

def RunAndLog(command, log_file):
    # Run the command and capture stdout and stderr
    p = subprocess.Popen(command, shell=False, 
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()

    # Check the return code and stderr
    if p.returncode != 0 or stderr:
        # Set up the logger
        logger = logging.getLogger('check_rel')
        logger.setLevel(logging.ERROR)

        file_handler = RotatingFileHandler(log_file, mode='a', maxBytes=0, 
                                           backupCount=0, encoding=None, delay=0)
        file_handler.setLevel(logging.ERROR)
        formatter = logging.Formatter('%(message)s')
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)

        # Log the stderr or a custom error message
        logger.error(f"Command failed with return code {p.returncode}")
        if stderr:
            logger.error(stderr.decode().strip())

        # Clean up the logger to avoid duplicate handlers
        logger.removeHandler(file_handler)
    return stdout, stderr, p.returncode

调用示例

假设要运行一个命令并记录失败的情况:

# Example: Running the directory listing command
command = ["ls", "/nonexistent/path"]  # Replace with your command
log_file = "test.log"

stdout, stderr, returncode = RunAndLog(command, log_file)
if returncode == 0:
    print("Command succeeded!")
else:
    print("Command failed. See test.log for details.")

主要改进点

  1. 检查退出状态码和 stderr:
  2. 如果 p.returncode 非零,表示命令失败,需要记录日志。
  3. 如果 stderr 非空,表示有错误输出,也需要记录日志。

  4. 日志记录改进:

  5. 只在命令失败或有错误输出时设置日志记录器并写入日志。
  6. 在日志消息中记录命令的返回码和错误输出。

  7. 避免日志处理器重复添加:

  8. 每次日志记录后,通过 logger.removeHandler 删除处理器,防止重复写入。

输出示例

当目录不存在:

test.log 会记录:

Command failed with return code 2
ls: cannot access '/nonexistent/path': No such file or directory

当命令成功:

不会写入 test.log

2024-12-29