Skip to content

COLDBOX-1467 FileAppender writes queued lines several times on Adobe ColdFusion - #727

Open
homestar9 wants to merge 2 commits into
ColdBox:developmentfrom
homestar9:fix/file-appender-duplicate-lines
Open

homestar9 wants to merge 2 commits into
ColdBox:developmentfrom
homestar9:fix/file-appender-duplicate-lines

Conversation

@homestar9

@homestar9 homestar9 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Description

On Adobe ColdFusion, FileAppender and RollingFileAppender write queued lines several times:
N lines queued together end up N + (N-1) + … + 1 times in the file, and each one is also printed
to the console.

The log listener passes its queue to preProcessQueue() as an argument. Adobe ColdFusion passes
arrays by value, so FileAppender's queue.clear() empties a copy. The listener then takes one
line off the real queue, prints it to the console through the base processQueueElement(), and
the next pass writes everything left again. Lucee and BoxLang pass arrays by reference, so they
are not affected. Setting this.passArrayByReference = true on ACF 2023 also makes the unchanged
code write each line once, which confirms the cause.

Changes:

  • AbstractAppender: a new private drainQueue() removes and returns the queued entries from
    the appender's own queue (variables.logListener.queue), so it works whichever way the engine
    passes arrays. It removes exactly the entries it read rather than calling clear(), so a line
    queued during the write is kept for the next pass. On every engine, that line could be lost
    before.
  • FileAppender.preProcessQueue() writes drainQueue() and ignores the argument.
  • FileAppender.processQueueElement() (new) writes a line the listener takes off the queue
    itself to the file instead of the console.
  • The preProcessQueue, postProcessQueue and processQueueElement docblocks now say the
    queue argument may be a copy and should only be read.

Hook signatures are unchanged, so custom appenders that override them keep working. The fix does
not depend on this.passArrayByReference, which most applications don't set.

Jira Issues

https://ortussolutions.atlassian.net/browse/COLDBOX-1467

Type of change

  • Bug Fix

Checklist

  • My code follows the style guidelines of this project cfformat
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Tests

New specs in FileAppenderTest.cfc, using a small test appender (QueueTestFileAppender.cfc)
that runs the listener in the test thread, so no sleeping is needed. The existing "can log
messages" spec now checks for an exact line count; before, it only checked that the text
appeared, which is why this was missed.

ACF 2023 ACF 2025 Lucee 6 BoxLang (CFML compat) BoxLang
New specs, before the fix 3 fail 3 fail 1 fails 1 fails 1 fails
All tests/specs/logging, after the fix 52 pass 52 pass 52 pass 52 pass 52 pass

RollingFileAppenderTest writes to the same MyFileAppender.log from its listener thread, so when it ran first the exact line count saw its leftover lines.
@homestar9
homestar9 marked this pull request as ready for review October 19, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant