Java 应用部署到 Ubuntu 之后,日志级别往往既影响排障效率,也直接关系到线上噪音和磁盘占用。要把日志调得稳妥,先要分清项目到底用了哪套日志框架,再根据配置文件、启动参数或临时调试场景选择合适做法;文末也补上 Ubuntu 下最常见的权限、路径覆盖和日志轮转判断点,方便快速落地。
先确认项目使用的是哪种日志框架
在动手改日志级别前,第一步不是直接写配置,而是先确认应用当前接入的是哪一种日志框架。不同框架的配置文件名、参数写法和覆盖方式都不一样,框架认错了,后面的修改通常不会生效。

Ubuntu 上常见的 Java 日志方案主要有三类:
- Log4j 2:功能比较完整,支持异步日志和动态配置,适合配置项较多、日志策略较复杂的项目。
- Logback:很多 Spring Boot 项目的默认选择,配置方式直观,性能和生态都比较成熟。
- java.util.logging(JUL):JDK 自带,不需要额外依赖,适合简单场景或一些基础服务。
如果项目是 Maven 或 Gradle 构建,通常可以先从依赖里看有没有 log4j-core、logback-classic 等关键包;如果已经打成 Jar 包运行,也可以先检查类路径中的配置文件名称,例如 log4j2.xml、logback.xml 或 logging.properties。
优先用配置文件设置日志级别
对大多数 Ubuntu 服务器上的 Java 应用来说,配置文件仍然是最稳妥的日志级别管理方式。它的好处很明确:配置集中、便于版本管理,也不会把运行时调试逻辑写进业务代码。通常配置文件会放在项目的 resources 目录下,或者在启动时通过命令行显式指定外部配置路径。
Log4j 2:通过 log4j2.xml 控制根级别和包级别
如果项目使用的是 Log4j 2,最常见的做法是编辑 log4j2.xml。下面这份示例同时配置了控制台输出和文件输出,并把全局根日志级别设为 info,同时对 com.example 包单独开启 debug。

这份配置里最值得关注的是两个点:
Root level:控制所有没有单独声明的包或类,常见可选值包括TRACE、DEBUG、INFO、WARN、ERROR、FATAL。Logger name:针对某个包或类做更细粒度设置,优先级高于根级别,适合只放大某一块业务的调试信息。
如果你只想在 Ubuntu 服务器上排查某个模块的问题,把根级别维持在 info,再给目标包单独开 debug,通常比全局打开 debug 更可控。
Logback:用 logback.xml 做常规生产配置
如果项目是 Spring Boot 或直接依赖 Logback,通常会使用 logback.xml。下面的示例同样包含控制台和文件输出,并启用了按天滚动的日志策略。

%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
logs/app.log
logs/app.%d{yyyy-MM-dd}.log
30
%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
这里的核心参数也很清晰:
root level:定义默认日志级别。logger name:给特定包或类单独调整输出级别。additivity="false":避免同一条日志沿父级 Logger 继续传递,导致重复输出。
在 Ubuntu 服务器上,Logback 常被直接用于生产环境,除了日志级别本身,更应该顺手把滚动策略一起配上。示例里的 TimeBasedRollingPolicy 就是典型做法,能按日期切分日志,并通过 maxHistory 控制保留天数。
JUL:使用 logging.properties 做基础配置
如果项目使用的是 JDK 自带的 java.util.logging,则配置通常落在 logging.properties 中。它的写法和前两者不同,但思路依然是“先定全局,再定输出处理器,最后按类覆盖”。
# 全局日志级别
.level=INFO
# 控制台Handler配置
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# 文件Handler配置
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.pattern=logs/app.log
java.util.logging.FileHandler.limit=50000
java.util.logging.FileHandler.count=5
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
# 特定类的日志级别(如com.example.MyClass设置为FINEST)
com.example.MyClass.level=FINEST
这类配置里需要重点看四项:
.level:全局默认级别。handlers:指定启用哪些输出处理器。java.util.logging.ConsoleHandler.level:控制台输出级别。com.example.MyClass.level:对某个类做精细化调整。
JUL 的优点是轻量,不需要额外依赖;但如果你希望配置方式更灵活、日志滚动能力更强,生产环境里往往还是 Log4j 2 或 Logback 更常见。
不改代码时,还可以用启动参数或环境变量
如果你不想直接改打包内的配置文件,或者只是想在 Ubuntu 上做一次临时切换,启动参数通常是效率最高的方式。它的本质是让应用在启动时显式加载指定配置,而不是使用类路径里的默认文件。
通过命令行参数指定配置文件
三种常见框架都支持用 -D 参数在启动时指定配置路径:
- Log4j 2:
java -Dlog4j.configurationFile=/path/to/log4j2.xml -jar your-app.jar - Logback:
java -Dlogback.configurationFile=/path/to/logback.xml -jar your-app.jar - JUL:
java -Djava.util.logging.config.file=/path/to/logging.properties -jar your-app.jar
这种做法特别适合以下场景:应用 Jar 包不方便重新打包、你需要在测试机和生产机之间复用不同日志策略,或者你想快速验证某份外部配置是否生效。实际使用时,建议直接给绝对路径,避免因为工作目录不同而找错文件。
部分框架可通过环境变量临时调整
某些框架还支持通过环境变量临时修改根日志级别,适合排障时快速放大日志输出,而不必进入项目目录改文件:
- Log4j 2:
export LOG4J_ROOT_LOGLEVEL=DEBUG && java -jar your-app.jar - Logback:
export LOGBACK_ROOT_LOGLEVEL=DEBUG && java -jar your-app.jar
这种方式方便,但更适合临时使用。原因是环境变量容易随着 shell、systemd 服务配置或部署脚本变化而失效,后续维护时也不如配置文件直观。
代码中动态改级别,只适合测试和应急
日志级别也可以在代码里直接修改,但这个入口更适合短期调试或应急处理,不适合作为常规生产配置。把日志策略写进业务代码,后续排查“为什么线上日志突然变多”时,成本往往更高。
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
public class Main {
private static final Logger logger = LogManager.getLogger(Main.class);
public static void main(String[] args) {
// 动态设置根日志级别为DEBUG
Configurator.setRootLevel(org.apache.logging.log4j.Level.DEBUG);
// 设置特定包的日志级别
Configurator.setLevel("com.example", org.apache.logging.log4j.Level.DEBUG);
logger.debug("Debug message"); // 此时将输出DEBUG日志
}
}
从示例可以看出,Log4j 2 可以通过 Configurator.setRootLevel 和 Configurator.setLevel 在运行时直接修改级别。这在本地调试时很实用,但线上长期保留这类逻辑,通常会让配置来源变得不透明。
Ubuntu 环境下最容易踩到的三个问题
同样一份 Java 日志配置,在本地能跑通,到了 Ubuntu 服务器上却未必生效。多数情况下问题不在“语法错了”,而是在系统环境、路径或文件管理策略上出了偏差。
日志目录存在且具备写权限
如果配置里把输出写到 logs/app.log,那就必须保证 logs/ 目录已经存在,而且运行 Java 进程的用户有写入权限。否则程序可能仍然启动成功,但日志文件就是写不出来,排查时会非常浪费时间。
一个常见处理方式是先检查目录,再授予合适权限,例如:
chmod 755 logs
这里的关键不是机械地执行某个命令,而是确认当前服务到底以哪个用户身份运行。如果应用是通过 systemd、CI 部署脚本或容器启动,真正需要写权限的未必是你当前登录的用户。
外部配置覆盖时,要注意加载顺序
日志框架通常会优先加载类路径中的默认配置,比如 src/main/resources/logback.xml。这意味着你即使在服务器上放了一份新的配置文件,如果没有通过启动参数显式指定,应用很可能仍然使用 Jar 包内部那份旧配置。
因此在 Ubuntu 上做外部覆盖时,最稳妥的办法还是使用前面提到的 -D 参数,并指定绝对路径。这样可以减少“我明明改了文件,但日志级别没变”的误判。
提前配置日志轮转,避免磁盘被持续占满
线上日志如果只追加不轮转,时间一长几乎一定会变成磁盘问题。尤其是临时把日志级别调到 DEBUG 之后,文件增长速度往往比预期更快。
比较稳妥的做法,是在框架配置里直接启用轮转策略:
- Logback 可使用
TimeBasedRollingPolicy。 - Log4j 可使用
RollingFileAppender。
无论按天切分还是按大小切分,核心目标都一样:让日志文件可控增长,并保留最近 N 份可追溯内容。这样即使为了定位问题临时提高日志级别,也不容易把 Ubuntu 服务器的磁盘空间迅速吃满。
实际落地时,怎么选最省事
如果只是给已有 Java 项目在 Ubuntu 上调整日志级别,最实用的决策顺序通常是这样的:先确认框架,再优先改配置文件;如果是临时调试,再考虑用 -D 参数或环境变量;只有在测试、联调或应急场景下,才考虑在代码中动态修改。
具体到生产实践,根日志级别一般维持在 INFO 或 WARN 更稳妥,需要排查某个模块时,再单独把目标包提升到 DEBUG。同时别忽略 Ubuntu 环境本身的三个前提:目录可写、外部配置路径明确、日志轮转已经启用。把这几项同时做到位,日志级别调整才算真正可用,而不只是“改了一个参数”。







