This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 5e94319e2ba3d764637a977c5f18f621f9ef7b4f
Author: opencode <[email protected]>
AuthorDate: Tue Oct 20 09:03:54 2026 +0200

    Open the current log file when no date is set
    
    FileHandler builds the name of the log file from the prefix, the as-of
    date of the currently open file and the suffix. The date is normally
    set by publish() just before it opens the writer, but a direct call to
    open(), the public API used to (re-)open a handler, ran with no date
    set, so the concatenation rendered the null date as the literal text
    null and created files such as catalina.null.log. Such a file never
    matches the pattern used for rotation and cleanup, so it lingered in
    the log directory. The reopen path of AsyncFileHandler, which opens a
    previously closed handler, was equally affected.
    
    The writer now opens the file of the current date when no date is set,
    computing the date in the same way as publish(), whose date logic was
    extracted to a shared helper. The computed date only becomes the
    handler's as-of date once the writer has been created successfully, so
    a failed open can still be retried by a subsequent publish. Added a
    regression test that opens a handler before any record was published,
    verifies the file of the current date is used for the record published
    afterwards, and that reopening a closed handler does not create files
    with an unset date.
---
 java/org/apache/juli/FileHandler.java     | 32 +++++++++++++++++++----
 test/org/apache/juli/TestFileHandler.java | 43 +++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/juli/FileHandler.java 
b/java/org/apache/juli/FileHandler.java
index 3ae058391d..13249c8e55 100644
--- a/java/org/apache/juli/FileHandler.java
+++ b/java/org/apache/juli/FileHandler.java
@@ -232,9 +232,7 @@ public class FileHandler extends Handler {
 
         final String tsDate;
         if (rotatable.booleanValue()) {
-            // Construct the timestamp we will use
-            Timestamp ts = new Timestamp(System.currentTimeMillis());
-            tsDate = ts.toString().substring(0, 10);
+            tsDate = obtainCurrentDate();
         } else {
             tsDate = "";
         }
@@ -449,7 +447,8 @@ public class FileHandler extends Handler {
 
 
     /**
-     * Open the new log file for the date specified by <code>date</code>.
+     * Open the new log file. If the handler is rotatable and no date has been 
set yet, the log file for the current
+     * date is opened.
      */
     public void open() {
         openWriter();
@@ -473,7 +472,16 @@ public class FileHandler extends Handler {
         FileOutputStream fos = null;
         OutputStream os = null;
         try {
-            File pathname = new File(dir.getAbsoluteFile(), prefix + 
(rotatable.booleanValue() ? date : "") + suffix);
+            // If no date has been set, typically because the handler has been 
opened before any record was
+            // published, use the current date, as publish() does when it 
rotates the log file, so the file
+            // name always matches the pattern used for rotation and cleanup
+            String currentDate = date;
+            boolean dateComputed = rotatable.booleanValue() && currentDate == 
null;
+            if (dateComputed) {
+                currentDate = obtainCurrentDate();
+            }
+            File pathname = new File(dir.getAbsoluteFile(),
+                    prefix + (rotatable.booleanValue() ? currentDate : "") + 
suffix);
             File parent = pathname.getParentFile();
             if (!parent.mkdirs() && !parent.isDirectory()) {
                 reportError("Unable to create [" + parent + "]", null, 
ErrorManager.OPEN_FAILURE);
@@ -486,6 +494,9 @@ public class FileHandler extends Handler {
             writer = new PrintWriter(
                     (encoding != null) ? new OutputStreamWriter(os, encoding) 
: new OutputStreamWriter(os), false);
             writer.write(getFormatter().getHead(this));
+            if (dateComputed) {
+                date = currentDate;
+            }
         } catch (Exception e) {
             reportError(null, e, ErrorManager.OPEN_FAILURE);
             writer = null;
@@ -508,6 +519,17 @@ public class FileHandler extends Handler {
         }
     }
 
+    /**
+     * Obtain the date string used as the date part of the names of the 
rotatable log files.
+     *
+     * @return The current date, formatted as <code>YYYY-MM-DD</code>
+     */
+    private static String obtainCurrentDate() {
+        // Construct the timestamp we will use
+        Timestamp ts = new Timestamp(System.currentTimeMillis());
+        return ts.toString().substring(0, 10);
+    }
+
     private void clean() {
         if (maxDays.intValue() <= 0 || Files.notExists(getDirectoryAsPath())) {
             return;
diff --git a/test/org/apache/juli/TestFileHandler.java 
b/test/org/apache/juli/TestFileHandler.java
index b6f4f2cdea..7b7d9725c5 100644
--- a/test/org/apache/juli/TestFileHandler.java
+++ b/test/org/apache/juli/TestFileHandler.java
@@ -23,6 +23,8 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -123,6 +125,47 @@ public class TestFileHandler {
         fh1.close();
     }
 
+    /*
+     * Opening a rotatable handler before any record has been published must 
open the log file for the current date,
+     * rather than a file whose name contains the string representation of the 
unset date. The same applies when a
+     * closed handler is opened again.
+     */
+    @Test
+    public void testOpenUsesCurrentDate() throws Exception {
+        String prefix = "opendate.";
+        String suffix = ".log";
+
+        FileHandler fh = new FileHandler(logsDir.getAbsolutePath(), prefix, 
suffix);
+        fh.open();
+
+        String today = LocalDate.now().toString();
+        File expected = new File(logsDir, prefix + today + suffix);
+        Assert.assertTrue("Expected file [" + expected + "] was not created", 
expected.isFile());
+
+        // Publishing after the open must use the file that was opened, not 
rotate to a new one
+        fh.publish(new LogRecord(Level.INFO, "hello"));
+        Assert.assertTrue("The published record was not written to [" + 
expected + "]",
+                Files.readString(expected.toPath()).contains("hello"));
+        Assert.assertEquals(1, countFiles(prefix));
+
+        // Reopening a closed handler must not create a file with an unset 
date either
+        fh.close();
+        fh.open();
+        Assert.assertEquals(1, countFiles(prefix));
+
+        fh.close();
+    }
+
+    private int countFiles(String prefix) {
+        int count = 0;
+        for (File file : logsDir.listFiles()) {
+            if (file.getName().startsWith(prefix)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
     private void generateLogFiles(File dir, String prefix, String suffix, int 
amount)
             throws IOException {
         for (int i = 0; i < amount; i++) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to