【WEB系列】内嵌Tomcat配置Accesslog日志文件生成位置源码探索

文章目录
  1. I. 项目搭建与日志配置
    1. 1. 项目依赖
    2. 2. tomcat日志配置
    3. 3. 一个简单的rest接口
  2. II. 日志文件目录定位
    1. 1. 源码定位
    2. 2. 小结
  3. III. 不能错过的源码和相关知识点
    1. 0. 项目
    2. 1. 微信公众号: 一灰灰Blog

现在SpringBoot应用大多是内嵌tomcat,以jar包方式启动对外提供服务,最近遇到一个有意思的问题,当我希望输出tomcat的 access.log 时,添加上对应的配置之后,发现windowns系统下找不到这个日志文件,而linux/mac则没有什么问题;

所以花了些时间定位一下,本文将记录定位这个日志文件生成的全过程,当发现最后的结论时,更让我吃惊的事情来了,就这么个问题,在三年前我也遇到过,只不过当时的问题是上传文件之后,提示临时目录不存在,而这个临时目录和本文定位的目录居然是一回事,可谓是来了一次梦幻的联动,前面踩的坑不探究到底,后面迟早会继续掉坑😂

I. 项目搭建与日志配置

1. 项目依赖

本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发

启动一个标准的SpringBoot项目,注意添加下面的依赖如下 (本文对应的源码可以在文末查看)

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. tomcat日志配置

tomcat的日志配置信息,下面放在默认的配置文件 application.yml 中,主要有下面几个关键参数

1
2
3
4
5
6
7
8
server:
port: 8080
tomcat:
accesslog:
enabled: true
directory: /tmp/logs/boot
file-date-format: .yyyyMMdd
pattern: '%h %l %u %t "%r" %s %b %Dms "%{Referer}i" "%{User-Agent}i" "%{X-Request-ID}i" "%{X-Forwarded-For}i"'

3. 一个简单的rest接口

添加一个基础的rest接口,用于接收请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RestController
@SpringBootApplication
public class Application {
private DalConfig dalConfig;

public Application(DalConfig dalConfig, Environment environment) {
this.dalConfig = dalConfig;
System.out.println(dalConfig);
}

public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.run(args);
}

@GetMapping(path = {"", "/", "/index"})
public ModelAndView index() {
return "hello";
}
}

接下来请求一下接口,看下日志是否正常

1
curl 'http://127.0.0.1:8080/'

如果是mac/linux系统的同学,就可以到 /tmp/logs/boot 目录下查看有没有对应的日志文件了,那么win的同学,到哪里看?

II. 日志文件目录定位

由于win和mac/linux对绝对路径的定义不同,就会导致我们用到这个问题,一般来说,实际的项目最终都是跑在linux系统上,所以文件路径以上面的case居多,很少会说加一个 c:d:开头的

那么问题就来了,同样一份代码,win开发的同学到哪里去找日志

1. 源码定位

我们这里讨论的是内嵌Tomcat,要想定位日志文件在哪里,就需要先找一下这个日志哪里输出的,

直接google搜索一下关键字,就可以得到有用的信息

上面的第一项,给出了一个核心的类 AccessLogValve,一下子就找到关键点了,核心地方打个端点,启动一下看看是怎样的

上面这个地址就是我们找的目标路径,那么这个是怎么来的呢?这个前缀有什么套路么?

核心来源点 File dir = this.getDirectoryFile();,对应的实现

1
2
3
4
5
6
7
8
9
private File getDirectoryFile() {
// 这个directory就是我们对应的配置参数 server.tomcat.access_log.directory
File dir = new File(this.directory);
if (!dir.isAbsolute()) {
dir = new File(this.getContainer().getCatalinaBase(), this.directory);
}

return dir;
}

所以重点需要关注 this.getContainer().getCatalinaBase(), 上面这个它对应的实例为org.apache.catalina.core.StandardEngine#getCatalinaBase

接着向上朔源,可以找到设置这个路径的地方,在org.apache.catalina.startup.Tomcat#initBaseDir

最后就是定位baseDir的初始化了,再网上找一下,可以看到关键信息

再直达一步,原来这个目录创建是基于 jdkFile.createTempFile()来实现的,又学到一个没什么鸟用的知识点了

2. 小结

本文可能对大部分小伙伴来说没什么鸟用,基本上也不太会有用到需要取查找tomcat的访问日志access.log的时候(这里指SpringBoot应用),在定位这个具体路径的时候,想起了很久之前也踩过的一个坑,上传文件时,提示临时目录不存在,而这个目录和我们上面查找定位的可以说是一个地方了,仔细看来,现在算是填了一个时隔三年的坑了😁

最后小结下本文对应的知识点

tip1 accesslog日志配置

核心配置信息如下

1
2
3
4
5
6
7
8
9
server:
port: 8080
tomcat:
accesslog:
enabled: true # 设置为true,表示输出 accesslog 日志
directory: /logs/boot # 日志文件所在的目录,注意不同操作系统,对绝对路径的定位不同
file-date-format: .yyyyMMdd # 按日期进行归档
pattern: '%h %l %u %t "%r" %s %b %Dms "%{Referer}i" "%{User-Agent}i" "%{X-Request-ID}i" "%{X-Forwarded-For}i"' # 日志输出格式,类似Logback配置
# basedir: /logs # 全局基本目录,如果配置,则日志文件对应的目录为 basedir + directory

tip2 绝对路径的判断

在Tomcat中,对于绝对路径的判断非常有参考价值,当然也可能是因为我对于jdk基本的api不够熟悉的原因 ,之前我的判断方式是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 是否windows系统
*/
public static boolean isWinOS() {
boolean isWinOS = false;
try {
String osName = System.getProperty("os.name").toLowerCase();
String sharpOsName = osName.replaceAll("windows", "{windows}").replaceAll("^win([^a-z])", "{windows}$1")
.replaceAll("([^a-z])win([^a-z])", "$1{windows}$2");
isWinOS = sharpOsName.contains("{windows}");
} catch (Exception e) {
e.printStackTrace();
}
return isWinOS;
}

public static boolean isAbsFile(String fileName) {
if (isWinOS()) {
// windows 操作系统时,绝对地址形如 c:\descktop
return fileName.contains(":") || fileName.startsWith("\\");
} else {
// mac or linux
return fileName.startsWith("/");
}
}

现在则有更简单的方式了

1
2
3
private boolean isAbs(String path) {
return new File(path).isAbsolute();
}

tip3 临时目录创建

同样是直接借助File来实现, File.createTempFile 即可,下面是Tomcat的创建方式,还非常贴心的加上了虚拟机终止时,自动删除相关的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Return the absolute temp dir for given web server.
* @param prefix server name
* @return the temp dir for given server.
*/
protected final File createTempDir(String prefix) {
try {
File tempDir = File.createTempFile(prefix + ".", "." + getPort());
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir;
}
catch (IOException ex) {
throw new WebServerException(
"Unable to create tempDir. java.io.tmpdir is set to " + System.getProperty("java.io.tmpdir"), ex);
}
}

III. 不能错过的源码和相关知识点

0. 项目

1. 微信公众号: 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到