Today is December 30, 2019. I logged into our online server and found that the log became "localhost_access_log.2020-12-30.log", which was a whole year away. All the monitoring graphs based on this log were scrapped, and I was panicked. I quickly debugged and found the SimpleDateFormat pit.
Let me talk about our environment first: springboot2.1.7 && built-in tomcat 9.0.22, and configured access log for tomcat, the specific configuration is as follows
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=********
server.tomcat.accesslog.prefix=localhost_access_log
server.tomcat.accesslog.suffix=.log
server.tomcat.accesslog.file-date-format=.YYYY-MM-dd
server.tomcat.accesslog.rotate=true
server.tomcat.accesslog.directory=logs
server.tomcat.basedir=./
Screenshot of the online log.
According to the log, debug tomcat all the way to initialize the application, and it turns out that the file in AccessLogValve
@Override
protected synchronized void startInternal() throws LifecycleException {
// Initialize the Date formatters
String format = getFileDateFormat();
fileDateFormatter = new SimpleDateFormat(format, Locale.US);
fileDateFormatter.setTimeZone(TimeZone.getDefault());
dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis())); // **出问题的地方**
if (rotatable && renameOnRotate) {
restore();
}
open();
super.startInternal();
}
Then manually wrote the test class, the problem reappeared
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", Locale.US);
long time = System.currentTimeMillis();
time = 1577601170000l; // 2019-12-29 14:32:50
String dateStamp = simpleDateFormat.format(new Date(time));
System.out.println(dateStamp);
}
Later, I looked at the jdk official website and found that there was a problem
with the time formatting expression . There are two Year and Week years in the figure above. Year is the year on the normal calendar, the latter refers to the official document . Simply put, December 30, 2019 is exactly the first day of the first week of the 2020 Week-year. So the result of "YYYY" is 2019.
After modifying the code, SimpleDateFormat df = new SimpleDateFormat(".yyyy.MM.dd");, you can get the correct result,
similar to "D" and "d". Therefore, "y" and "d" should be used in most cases.
As follows:
public static void main(String[] args) {
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd", Locale.US);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
long time = System.currentTimeMillis();
time = 1577601170000l; // 2019-12-29 14:32:50
String dateStamp = simpleDateFormat.format(new Date(time));
System.out.println(dateStamp);
}
This detail is usually not paid attention to. Fortunately, it only appears on the log name today, otherwise the impact cannot be assessed.