7.5 Tomcat 日志分析与故障排查


文档摘要

7.5 Tomcat 日志分析与故障排查 7.5 Tomcat 日志分析与故障排查 7.5.1 Tomcat 日志类型概览 Tomcat 拥有完善的日志体系,记录了服务器运行的各个环节的信息。根据日志内容和用途,Tomcat 日志主要可以分为以下几类: catalina.out 和 catalina.log: 这两个文件通常记录 Tomcat 启动、关闭以及运行过程中的一些关键信息,例如 JVM 信息、异常堆栈、以及一些重要的警告和错误信息。 默认会将 和 的输出重定向到该文件,而 则是由 Tomcat 的日志框架生成的日志,内容上两者可能存在重叠,但侧重点略有不同。在 Linux 系统中,通常使用 ,而在 Windows 系统中,则可能更多使用 。 localhost.

7.5 Tomcat 日志分析与故障排查

7.5 Tomcat 日志分析与故障排查

7.5.1 Tomcat 日志类型概览

Tomcat 拥有完善的日志体系,记录了服务器运行的各个环节的信息。根据日志内容和用途,Tomcat 日志主要可以分为以下几类:

  • catalina.out 和 catalina.log: 这两个文件通常记录 Tomcat 启动、关闭以及运行过程中的一些关键信息,例如 JVM 信息、异常堆栈、以及一些重要的警告和错误信息。catalina.out 默认会将 System.outSystem.err 的输出重定向到该文件,而 catalina.log 则是由 Tomcat 的日志框架生成的日志,内容上两者可能存在重叠,但侧重点略有不同。在 Linux 系统中,通常使用 catalina.out,而在 Windows 系统中,则可能更多使用 catalina.log

  • localhost.log: 该日志文件主要记录部署在 localhost Host 上的 Web 应用相关的日志信息,例如 Web 应用的部署、启动、停止过程中的信息,以及在 Web 应用运行过程中抛出的未被应用自身日志框架捕获的异常信息。对于默认的 Host (localhost),这个日志文件非常重要,可以帮助我们了解 Web 应用的部署状态和运行状况。

  • localhost_access_log.txt: 这是一个访问日志文件,记录了所有访问 localhost Host 上 Web 应用的请求信息。每一行日志代表一个 HTTP 请求,包含了请求的时间、客户端 IP、请求方法、URI、HTTP 协议、响应状态码、发送的字节数、请求头信息(例如 User-Agent, Referer)等详细信息。访问日志对于分析用户行为、性能瓶颈、安全审计等方面都具有重要价值。

  • manager.log 和 host-manager.log: 这两个日志文件分别记录了 Tomcat Manager 应用和 Host Manager 应用的日志信息。Manager 应用用于管理 Tomcat 服务器上的 Web 应用,例如部署、卸载、启动、停止应用等。Host Manager 应用则用于管理 Tomcat 服务器上的虚拟主机。这两个日志文件对于排查 Manager 和 Host Manager 应用自身的问题,以及通过它们进行管理操作时出现的问题非常有用。

  • 应用程序日志 (Application Logs): 除了 Tomcat 自身生成的日志外,部署在 Tomcat 中的 Web 应用通常也会使用日志框架 (例如 Log4j, Logback, java.util.logging) 生成应用程序日志。这些日志的内容完全由应用程序自身控制,记录了应用程序运行时的各种信息,例如业务逻辑执行过程、异常信息、性能数据等。应用程序日志是排查 Web 应用内部问题的最直接的依据。日志文件的名称、格式、存储位置等通常在应用程序的日志配置文件中进行配置。

为了更清晰地展示 Tomcat 日志体系的结构,我们可以使用 Mermaid 的 graph TD 图进行可视化:

图 7.5.1 Tomcat 日志类型概览

7.5.2 日志格式详解与配置

理解日志文件的格式是进行有效日志分析的基础。不同类型的 Tomcat 日志文件,其格式有所不同,并且可以进行自定义配置。

7.5.2.1 catalina.out 和 catalina.log 格式

catalina.outcatalina.log 的格式相对简单,通常是文本形式,每一行代表一条日志记录。日志记录通常包含时间戳、日志级别(例如 INFO, WARNING, ERROR)、日志来源组件、以及具体的日志消息。例如:

2023-10-27 10:00:00,000 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/9.0.x 2023-10-27 10:00:01,000 WARNING [localhost-startStop-1] org.apache.catalina.startup.ContextConfig.beforeStart Web application context [/myapp] will be started after web.xml is processed 2023-10-27 10:00:02,000 ERROR [http-nio-8080-exec-1] org.apache.catalina.connector.CoyoteAdapter.service An exception occurred processing JSP page /index.jsp at line 10

日志级别通常包括:

  • TRACE: 最详细的日志信息,通常用于开发调试。

  • DEBUG: 调试信息,比 TRACE 级别信息少一些,也用于开发调试。

  • INFO: 一般性的信息,例如服务器启动信息、应用部署信息等。

  • WARNING: 警告信息,表示可能存在潜在问题,但不一定会影响服务器运行。

  • ERROR: 错误信息,表示发生了错误,可能影响部分功能或应用运行。

  • FATAL: 致命错误,表示发生了严重错误,可能导致服务器崩溃或无法正常运行。

可以通过修改 Tomcat 的 logging.properties 文件来配置 catalina.outcatalina.log 的日志级别、日志格式等。

7.5.2.2 localhost_access_log.txt 格式

localhost_access_log.txt 默认使用 Common Log Format (CLF)Combined Log Format (CLF)

Common Log Format (CLF) 格式如下:

remotehost rfc931 authuser [date] "request" status bytes

例如:

127.0.0.1 - - [27/Oct/2023:10:00:00 +0800] "GET /myapp/index.jsp HTTP/1.1" 200 1234

字段含义:

  • remotehost: 客户端 IP 地址。

  • rfc931: 远程登录名 (通常为 -)。

  • authuser: 认证用户名 (通常为 -)。

  • [date]: 请求时间,格式为 [day/month/year:hour:minute:second zone]

  • "request": 请求行,包含请求方法、URI 和 HTTP 协议。

  • status: HTTP 响应状态码。

  • bytes: 发送给客户端的字节数。

Combined Log Format (CLF) 格式在 CLF 的基础上增加了 RefererUser-Agent 请求头信息:

remotehost rfc931 authuser [date] "request" status bytes "Referer" "User-Agent"

例如:

127.0.0.1 - - [27/Oct/2023:10:00:00 +0800] "GET /myapp/index.jsp HTTP/1.1" 200 1234 "http://localhost:8080/myapp/index.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"

除了 CLF 和 Combined Log Format,Tomcat 还支持自定义访问日志格式,通过配置 server.xml 文件中的 <Valve> 元素来实现。

7.5.2.3 Access Log 配置

访问日志的配置主要在 Tomcat 的 server.xml 文件中完成。在 <Host> 元素内部,可以添加 <Valve> 元素来配置访问日志。

一个典型的访问日志配置示例:

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" resolveHosts="false"/> </Host>

关键配置参数:

  • className: 指定 AccessLogValve 的类名,固定为 org.apache.catalina.valves.AccessLogValve

  • directory: 指定日志文件存储目录,相对于 Tomcat 的 catalina.base 目录。

  • prefix: 指定日志文件名前缀。

  • suffix: 指定日志文件后缀。

  • pattern: 指定日志格式模式,可以使用预定义的模式 (例如 common, combined),也可以自定义模式。

  • resolveHosts: 是否解析主机名,设置为 false 可以提升性能,但日志中只会记录 IP 地址。

自定义日志格式模式 (pattern)

pattern 属性可以使用多种占位符来定义日志格式,常用的占位符包括:

  • %a: 客户端 IP 地址。

  • %A: 服务器 IP 地址。

  • %b: 发送的字节数,不包括 HTTP 头部,如果为 0 则输出 -

  • %B: 发送的字节数,不包括 HTTP 头部,总是输出数字,如果为 0 则输出 0

  • %h: 远程主机名 (如果 resolveHosts="true") 或客户端 IP 地址 (如果 resolveHosts="false",推荐)。

  • %H: 请求协议。

  • %l: 远程逻辑用户名 (始终为 -)。

  • %m: 请求方法。

  • %p: 服务器端口。

  • %q: 查询字符串 (如果存在,以 ? 开头)。

  • %r: 请求行 (完整请求,例如 "GET /myapp/index.jsp HTTP/1.1")。

  • %s: HTTP 响应状态码。

  • %t: 请求时间,Common Log Format 格式。

  • %T: 处理请求的时间,单位为秒。

  • %D: 处理请求的时间,单位为毫秒。

  • %u: 远程认证用户名 (如果没有认证则为 -)。

  • %U: 请求 URI。

  • %{header-name}i: 请求头信息,例如 %{User-Agent}i

  • %{header-name}o: 响应头信息,例如 %{Content-Type}o

  • %{attribute-name}c: ServletRequest 属性。

  • %{attribute-name}s: HttpSession 属性。

  • %{attribute-name}r: ServletContext 属性。

  • %{cookie-name}C: Cookie 信息。

例如,要记录请求处理时间 (毫秒) 和 User-Agent,可以自定义 pattern 为:

pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{User-Agent}i&quot;"

代码实践示例:配置访问日志 (server.xml)

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- 配置自定义格式的访问日志,包含请求处理时间和 User-Agent --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{User-Agent}i&quot;" resolveHosts="false"/> </Host>

7.5.3 日志分析工具与技巧

掌握日志分析工具和技巧可以大幅提升故障排查效率。

7.5.3.1 常用命令行工具

对于文本格式的日志文件,一些常用的命令行工具可以帮助我们快速分析日志:

  • grep: 用于搜索匹配特定模式的行。例如,查找包含 "ERROR" 关键词的日志行:

    grep "ERROR" catalina.out

    可以使用 -i 参数忽略大小写, -n 参数显示行号, -r 参数递归搜索目录等。

  • tail: 用于查看文件末尾的内容,常用于实时监控日志。例如,实时查看 catalina.out 的最新日志:

    tail -f catalina.out

    可以使用 -n 参数指定显示的行数。

  • awk: 强大的文本处理工具,可以根据字段分隔符处理日志行。例如,提取访问日志中的客户端 IP 地址和请求 URI:

    awk '{print $1, $7}' localhost_access_log.txt
  • sed: 流编辑器,用于对文本进行替换、删除等操作。例如,将日志文件中的 "WARNING" 替换为 "WARN":

    sed 's/WARNING/WARN/g' catalina.out > catalina.out.new
  • sort: 用于对文本行进行排序。例如,按照访问日志中的响应时间 (假设响应时间是第 9 个字段) 排序:

    sort -k 9 -n localhost_access_log.txt
  • uniq: 用于去除重复的行。结合 sort 可以统计日志中重复行的数量。例如,统计访问日志中不同 IP 地址的访问次数:

    awk '{print $1}' localhost_access_log.txt | sort | uniq -c | sort -nr

7.5.3.2 日志聚合与分析平台

当日志量较大,或者需要进行更复杂的分析时,可以使用专业的日志聚合与分析平台,例如:

  • ELK/EFK Stack (Elasticsearch, Logstash/Fluentd, Kibana): 开源的日志管理和分析平台,功能强大,可用于日志收集、存储、搜索、可视化和告警。

  • Splunk: 商业化的日志管理和分析平台,功能全面,易用性好,但成本较高。

  • Graylog: 开源的日志管理平台,专注于日志收集和分析,易于部署和使用。

这些平台通常提供以下功能:

  • 集中式日志收集: 从多台服务器收集日志,统一存储。

  • 结构化日志解析: 将非结构化的日志数据解析为结构化数据,方便查询和分析。

  • 强大的搜索功能: 支持全文搜索、关键词搜索、字段搜索、时间范围搜索等。

  • 可视化分析: 提供仪表盘、图表等可视化工具,帮助用户直观地理解日志数据。

  • 告警功能: 可以根据日志内容设置告警规则,及时发现异常情况。

7.5.3.3 实时日志监控

使用 tail -f 命令可以实时监控日志文件的变化。结合 grep 可以实时过滤和高亮显示感兴趣的日志信息。例如,实时监控 catalina.out 并高亮显示 "ERROR" 行:

tail -f catalina.out | grep --color=auto "ERROR"

7.5.3.4 关键词、时间戳、错误码搜索

在日志分析中,常用的搜索方法包括:

  • 关键词搜索: 根据错误信息、异常类型、组件名称等关键词搜索日志。

  • 时间戳搜索: 根据问题发生的时间范围,筛选日志。

  • 错误码搜索: 根据特定的错误码 (例如 HTTP 状态码、应用程序自定义错误码) 搜索日志。

7.5.3.5 分析线程转储 (Thread Dump) 和堆转储 (Heap Dump)

当 Tomcat 出现性能问题、死锁、内存溢出等问题时,可以生成线程转储 (Thread Dump) 和堆转储 (Heap Dump) 文件进行分析。

  • 线程转储 (Thread Dump): 记录了 JVM 中所有线程的运行状态,可以帮助分析线程死锁、CPU 占用过高等问题。可以使用 jstack 命令生成线程转储文件。

  • 堆转储 (Heap Dump): 记录了 JVM 堆内存的快照,可以帮助分析内存泄漏、内存溢出等问题。可以使用 jmapjconsole 等工具生成堆转储文件。

线程转储和堆转储文件通常需要专业的分析工具 (例如 VisualVM, MAT - Memory Analyzer Tool) 进行分析。

7.5.4 常见 Tomcat 故障排查案例

本节将结合实际案例,演示如何利用 Tomcat 日志进行故障排查。

7.5.4.1 启动失败排查

故障现象: Tomcat 启动失败,控制台或 catalina.out 中出现错误信息。

排查步骤:

  1. 查看 catalina.outcatalina.log: 这是排查启动失败的首要步骤。仔细查看日志文件,寻找 ERRORFATAL 级别的错误信息。

  2. 检查端口冲突: 常见的启动失败原因是端口被占用。日志中可能会出现类似 "Address already in use" 的错误信息。可以使用 netstat -tulnp (Linux) 或 netstat -ano (Windows) 命令查看端口占用情况,并找出占用端口的进程。

  3. 检查配置文件错误: 检查 server.xml, web.xml, context.xml 等配置文件是否存在语法错误或配置错误。日志中可能会提示配置文件的错误位置和类型。

  4. 检查依赖缺失: 如果 Web 应用依赖的 JAR 包缺失,Tomcat 启动时可能会报错。检查 localhost.log 和应用程序日志,查看是否有 ClassNotFoundExceptionNoClassDefFoundError 等异常。

  5. 检查 JDK 版本: 确认 Tomcat 运行所需的 JDK 版本是否正确安装和配置。日志中可能会提示 JDK 版本不兼容的错误信息。

Mermaid 图示:启动失败排查流程

代码实践示例:端口冲突排查

假设 catalina.out 中出现以下错误信息:

java.net.BindException: Address already in use: bind

可以使用 netstat -tulnp 命令 (Linux) 查看 8080 端口是否被占用:

netstat -tulnp | grep 8080

如果输出结果显示 8080 端口被其他进程占用,则需要修改 Tomcat 的 server.xml 文件,将 Connector 的 port 属性修改为未被占用的端口。

7.5.4.2 应用部署失败排查

故障现象: Web 应用部署失败,Tomcat 控制台或 localhost.log 中出现错误信息。

排查步骤:

  1. 查看 localhost.log: 这是排查应用部署失败的关键日志文件。查看日志中是否有 ERRORWARNING 级别的错误信息,特别是与应用部署相关的日志。

  2. 检查 Context Path 冲突: 如果多个 Web 应用使用了相同的 Context Path,部署时会发生冲突。日志中可能会提示 "Context path [/myapp] is already in use" 的错误信息。检查 server.xml, context.xml 或 WAR 包中的 META-INF/context.xml 文件,确保 Context Path 的唯一性。

  3. 检查 Web 应用配置错误: 检查 Web 应用的 web.xml 文件、Spring 配置文件、或其他配置文件是否存在语法错误或配置错误。日志中可能会提示配置文件的错误位置和类型。

  4. 检查依赖缺失: Web 应用依赖的 JAR 包缺失也可能导致部署失败。检查 localhost.log 和应用程序日志,查看是否有 ClassNotFoundExceptionNoClassDefFoundError 等异常。

  5. 检查资源冲突: 例如,JNDI 资源配置冲突、数据库连接池配置错误等也可能导致部署失败。检查 context.xml 和应用程序日志,查看是否有资源配置相关的错误信息。

Mermaid 图示:应用部署失败排查流程

代码实践示例:Context Path 冲突排查

假设 localhost.log 中出现以下错误信息:

2023-10-27 10:00:05.000 ERROR [localhost-startStop-1] org.apache.catalina.startup.ContextConfig.contextConfig Context path [/myapp] is already in use

需要检查 Tomcat 的 server.xml 文件、各个 Web 应用的 context.xml 文件,以及部署的 WAR 包,找出是否多个应用使用了相同的 Context Path /myapp,并修改其中一个应用的 Context Path。

7.5.4.3 500 错误排查

故障现象: 用户访问 Web 应用时,返回 HTTP 500 错误。

排查步骤:

  1. 查看访问日志 (localhost_access_log.txt): 确认 500 错误是否真实发生,以及发生的时间和请求 URI。

  2. 查看应用程序日志: 500 错误通常是应用程序内部错误导致的。查看应用程序日志,查找错误发生时间附近的 ERROR 级别日志,特别是异常堆栈信息。

  3. 查看 localhost.log: 如果应用程序日志没有详细的错误信息,可以查看 localhost.log,看是否有未被应用程序捕获的异常信息。

  4. 分析异常堆栈: 仔细分析异常堆栈信息,定位错误发生的具体代码位置和原因。常见的 500 错误原因包括:空指针异常、数据库连接异常、IO 异常、业务逻辑错误等。

  5. 复现问题: 尝试复现 500 错误,以便进行更详细的调试和分析。

Mermaid 图示:500 错误排查流程

代码实践示例:分析 500 错误日志

假设应用程序日志中出现以下异常堆栈:

2023-10-27 10:00:10.000 ERROR [http-nio-8080-exec-2] com.example.myapp.MyServlet.doGet Servlet.service() for servlet [MyServlet] in context with path [/myapp] threw exception [java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null] with root cause java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null at com.example.myapp.MyServlet.doGet(MyServlet.java:20) at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ...

根据异常堆栈信息,可以定位到错误发生在 com.example.myapp.MyServlet.doGet 方法的第 20 行,原因是 name 变量为 null,导致 String.length() 方法调用时抛出 NullPointerException。根据这个信息,可以进一步查看 MyServlet.java 的代码,分析 name 变量为空的原因,并修复代码。

7.5.4.4 性能问题排查

故障现象: Web 应用响应速度变慢,用户体验下降。

排查步骤:

  1. 查看访问日志 (localhost_access_log.txt): 分析访问日志,查看平均响应时间、最大响应时间、慢请求 URI 等信息。可以使用 awk 或其他工具统计响应时间分布。

  2. 监控 Tomcat 性能指标: 使用 JConsole, VisualVM, 或 Prometheus + Grafana 等监控工具,监控 Tomcat 的 CPU 使用率、内存使用率、线程池状态、连接数等性能指标。

  3. 分析线程转储 (Thread Dump): 如果 CPU 使用率过高,或者出现请求阻塞,可以生成线程转储文件,分析线程状态,查找 CPU 密集型线程或阻塞线程。

  4. 分析堆转储 (Heap Dump): 如果内存使用率过高,或者频繁发生 Full GC,可以生成堆转储文件,分析内存泄漏或内存溢出问题。

  5. 检查应用程序性能: 如果 Tomcat 自身性能指标正常,问题可能出在应用程序内部。需要使用 Profiler 工具 (例如 JProfiler, YourKit) 分析应用程序的性能瓶颈,例如慢 SQL 查询、IO 操作、算法效率低等。

Mermaid 图示:性能问题排查流程

代码实践示例:分析访问日志中的慢请求

使用 awk 命令统计访问日志中响应时间超过 1 秒的请求 URI:

awk '$9 >= 1000 {print $7, $9}' localhost_access_log.txt

输出结果会列出响应时间超过 1 秒的请求 URI 和响应时间 (毫秒),可以根据这些信息进一步分析慢请求的原因。

7.5.4.5 会话管理问题排查

故障现象: 用户会话丢失、会话失效、会话数据异常等问题。

排查步骤:

  1. 查看应用程序日志: 检查应用程序日志,查找与会话管理相关的错误信息或警告信息。

  2. 检查 Session Cookie: 使用浏览器开发者工具,检查请求和响应的 Cookie 信息,确认 Session Cookie 是否正确设置和传递。

  3. 检查 Session 持久化配置: 如果使用了 Session 持久化 (例如基于文件、数据库、Redis 等),检查持久化配置是否正确,持久化存储是否正常工作。

  4. 检查 Session 超时配置: 检查 web.xmlcontext.xml 中 Session 超时配置是否合理,是否过短导致会话频繁失效。


发布者: 作者: 转发
评论区 (0)
U