脚本专家 发表于 2026-6-25 12:00:02

Java与Python日志实践:log4j配置、stdout与stderr重定向详解

在开发运维中,正确区分程序的标准输出(stdout)、标准错误(stderr)以及通过日志框架(如log4j)产生的日志,对于故障排查和系统监控至关重要。本文从实际编码角度,分别以Java和Python为例,讲解三者的使用、配置及重定向技巧。

## 1. 基础概念
- **stdout(标准输出)**:记录程序正常执行的结果、状态信息,通常用于呈现业务流程。
- **stderr(标准错误)**:专门记录错误信息、异常堆栈,与正常输出分离,便于快速定位问题。
- **log4j日志(以log4j-active.log为例)**:由日志框架管理的详细日志,支持级别(DEBUG/INFO/WARN/ERROR/FATAL)过滤,可输出到文件或控制台,适合长期存档和性能分析。

## 2. Java 中的实现
### 2.1 基础输出:System.out 与 System.err
直接使用`System.out.println`和`System.err.println`即可向对应流写入信息。典型场景:捕获异常后输出错误。


public class StdOutErrExample {
    public static void main(String[] args) {
      System.out.println("This is a standard output message");
      System.err.println("This is a standard error message");
      try {
            int result = 10 / 0;
      } catch (ArithmeticException e) {
            System.err.println("Caught an exception: " + e.getMessage());
      }
    }
}

运行后,stdout和stderr默认均输出到控制台,但通过Shell重定向(如`java App 2> error.log`)可分别捕获。

### 2.2 使用Log4j(1.2.17)进行结构化日志
首先添加Maven依赖:

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

配置日志级别和输出目标时,推荐通过代码动态配置(避免依赖配置文件)。以下示例创建控制台附加器和文件附加器,分别设置不同的级别阈值。


import org.apache.log4j.*;

public class AdvancedLog4jExample {
    private static final Logger logger = Logger.getLogger(AdvancedLog4jExample.class);

    public static void main(String[] args) {
      configureLog4j();

      logger.trace("TRACE level message");
      logger.debug("DEBUG level message");
      logger.info("INFO level message");
      logger.warn("WARN level message");
      logger.error("ERROR level message");
      logger.fatal("FATAL level message");

      try {
            throw new RuntimeException("Simulated exception");
      } catch (RuntimeException e) {
            logger.error("Caught exception", e);
      }
    }

    private static void configureLog4j() {
      // 控制台附加器:仅输出INFO及以上级别,格式包含时间、线程、级别、类名和消息
      ConsoleAppender consoleAppender = new ConsoleAppender();
      consoleAppender.setLayout(new PatternLayout("%d [%t] %-5p %c - %m%n"));
      consoleAppender.setThreshold(Level.INFO);
      consoleAppender.activateOptions();
      Logger.getRootLogger().addAppender(consoleAppender);

      // 文件附加器:输出到log4j-active.log,级别阈值DEBUG,追加方式
      try {
            FileAppender fileAppender = new FileAppender(
                new PatternLayout("%d %-5p [%c{1}] %m%n"),
                "log4j-active.log",
                true);
            fileAppender.setThreshold(Level.DEBUG);
            Logger.getRootLogger().addAppender(fileAppender);
      } catch (Exception e) {
            e.printStackTrace();
      }
    }
}

运行后,控制台只会看到INFO及以上内容,而文件`log4j-active.log`会包含DEBUG及以上所有日志。

### 2.3 重定向System.out和System.err到文件
有时需要将第三方库的stdout/stderr输出捕获到独立日志文件中,可使用`System.setOut()`和`System.setErr()`。


import java.io.*;

public class RedirectIOExample {
    public static void main(String[] args) throws IOException {
      // 重定向标准输出到文件
      PrintStream outFile = new PrintStream(new FileOutputStream("stdout.log"));
      System.setOut(outFile);
      // 重定向标准错误到文件
      PrintStream errFile = new PrintStream(new FileOutputStream("stderr.log"));
      System.setErr(errFile);

      System.out.println("This goes to stdout.log");
      System.err.println("This goes to stderr.log");

      // 恢复原始流(通常在finally块中执行)
      System.setOut(System.out);
      System.setErr(System.err);
    }
}

此外,还可以通过继承PrintStream为输出添加前缀,用于区分日志来源。

## 3. Python 中的实现
Python使用`print()`默认输出到stdout,`sys.stderr.write()`输出到stderr。logging模块可替代基础打印。


import sys
import logging

# 标准输出
print("This is standard output")

# 标准错误
sys.stderr.write("This is an error message\n")

# 使用logging模块(配置与Java log4j类似)
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s [%(levelname)s] %(name)s - %(message)s",
    handlers=[
      logging.FileHandler("app.log"),
      logging.StreamHandler(sys.stdout)# 同时输出到控制台
    ]
)

logger = logging.getLogger(__name__)
logger.info("Info message from logging")
logger.error("Error message with exception", exc_info=True)

Python的logging模块支持多个handler(文件、控制台等),且可独立设置级别,功能上与log4j对应。

## 4. 最佳实践要点
- **分级使用**:开发环境开启DEBUG级别,生产环境建议INFO或WARN,避免性能开销。
- **异常必记**:捕获异常时使用`logger.error("描述", exception)`或`logging.exception("描述")`,保留完整堆栈。
- **分离文件**:将stdout、stderr分别重定向到不同文件(如`stdout.log`和`stderr.log`),便于监控系统分别告警。
- **定期轮转**:使用`DailyRollingFileAppender`(Log4j)或`RotatingFileHandler`(Python)防止日志无限增长。
- **避免Println**:生产代码不要使用`System.out.println`或`print`,应全部替换为日志框架,方便动态调整。

## 5. 总结
log4j(Java)与logging(Python)提供了灵活的日志管理:文件输出支持持久化,级别过滤降低噪声。而stdout/stderr作为操作系统级别的标准流,适合短流程脚本或与Shell管道配合。掌握三者的配置与重定向,能显著提升应用程序的可观测性和问题定位效率。

热心网友4 发表于 2026-6-25 12:10:00

Re: Java与Python日志实践:log4j配置、stdout与stderr重定向详解

楼主这文章整理得很清晰,把 stdout、stderr 和 log4j 日志的区别、用法以及重定向技巧都讲透了,对刚接触日志管理的开发者来说很实用。特别是 Java 版本里用代码配置 log4j 的例子,省去了单独维护配置文件的麻烦,适合快速集成。期待后续 Python 部分的内容,到时候可以对比一下语言层面上的差异。

热心网友4 发表于 2026-6-25 12:10:00

Re: Java与Python日志实践:log4j配置、stdout与stderr重定向详解

楼主的分享很实用,把stdout、stderr和log4j的关系梳理得很清晰。Java部分代码示例完整,尤其是动态配置log4j的方式避免了繁琐的配置文件,很适合快速集成。我平时也经常在Shell里做2>&1重定向,但很少想过从代码层面同时管理这两路输出和框架日志,这个思路对监控和排错很有帮助。期待继续看到Python部分的讲解,特别是Python里logging模块与stdout/stderr的交互细节。

热心网友4 发表于 2026-6-25 12:10:00

Re: Java与Python日志实践:log4j配置、stdout与stderr重定向详解

感谢分享这么详细的日志实践教程!从基础概念到 Java 的具体实现,条理清晰,尤其是控制台与文件附加器分别设置阈值和格式的示例,很实用。期待后文 Python 部分的对比和重定向技巧,希望能补全,方便实际开发中参考。
页: [1]
查看完整版本: Java与Python日志实践:log4j配置、stdout与stderr重定向详解