BoxLang 🚀 A New JVM Dynamic Language Learn More...

Single File Stachebox Appender

v1.0.0 Modules

Single File Stachebox Appender

ForgeBox

A minimal, self-contained ColdBox module that ships LogBox entries to a Stachebox instance over HTTP. It replaces the logstash module (and its bundled cbelasticsearch, hyper and cbrestbasehandler dependencies) for applications that only send logs to a remote Stachebox — the transmission: "api" mode.

The problem this solves

The stock setup was: logstash module in api mode, posting entries to a central Stachebox instance. No local Elasticsearch exists on the application servers. Despite that, the application intermittently failed to boot after a restart:

lucee.runtime.exp.LockException: a timeout occurred after 20 seconds trying to
acquire a exclusive lock with name [module....activation.logstash]

followed by key [cbController] doesn't exist on every request — the site never came back online.

Root cause, in the logstash module (v3.1.1):

  1. In api mode the module registers logstash.models.logging.APIAppender.
  2. APIAppender extends cbelasticsearch.models.logging.LogstashAppender and only overrides logMessage(). It inherits onRegistration().
  3. LogBox calls onRegistration() when the appender is registered — during module activation, inside ColdBox's exclusive per-module activation lock.
  4. The inherited onRegistration() runs ensureDataStream(): ILM policy, ingest pipeline, index/component templates — all against the cbelasticsearch client, whose unconfigured default host is 127.0.0.1:9200.
  5. With no local Elasticsearch that call blocks until it times out, while holding the activation lock. Concurrent requests hit the 20-second lock timeout, ColdBox never finishes loading, application[cbController] is never set, and the application stays down.

So an appender whose only job was "POST JSON to a URL" was taking the site down over an Elasticsearch it was never supposed to talk to — and dragged in three dependency modules to do it.

The approach

Everything the old stack actually did for us fits in one appender CFC with no dependencies (models/StacheboxAppender.cfc):

  • Marshal the log event into the same entry format the cbelasticsearch LogstashAppender produced (ECS-style keys, source-context frames for exceptions, error.stack_trace/frames/extrainfo as JSON strings, yyyy-mm-dd'T'HH:nn: ssZZ timestamps).
  • Sign each entry with the identical stachebox.signature hash (same fields, same order), so occurrences keep grouping with entries logged by the old module.
  • Send { "entry": ..., "dataStream": ... } with a Bearer token to the Stachebox API from a fire-and-forget cfthread — the request never waits on the log target, and a send failure only prints to stderr.

Module activation does zero I/O: onLoad() just registers the appender on the root logger. An unreachable Stachebox can no longer affect application startup or requests.

Deliberately dropped from the old module: direct-to-Elasticsearch mode, the log-receiving API endpoints, detached appenders, and the userInfoUDF hook. If per-user context is ever needed again, extend the user key in marshallLogObject().

Installation

Available on ForgeBox:

box install singleFileStacheboxAppender

Source and issue tracker: github.com/akitogo/singleFileStacheboxAppender

Configuration

In config/Coldbox.cfc (or config/modules/singleFileStacheboxAppender.cfc):

moduleSettings = {
    "singleFileStacheboxAppender" = {
        "apiUrl"          : "https://stachebox.example.com/logstash/api/logs",
        "apiAuthToken"    : "<bearer token>",
        "applicationName" : "my-app",
        "levelMin"        : "FATAL",
        "levelMax"        : "INFO"
    }
};
Setting Default Purpose
enabled true Master switch
apiUrl (empty — appender not registered) Stachebox log intake endpoint
apiAuthToken (empty) Authorization: Bearer token
applicationName application nameGrouping label in Stachebox
dataStream logs-coldbox-logstash-appender Data stream name sent with each entry
levelMin FATAL Minimum severity
levelMax INFO Maximum severity

$ box install singleFileStacheboxAppender

No collaborators yet.
     
  • {{ getFullDate("2026-07-14T20:10:03Z") }}
  • {{ getFullDate("2026-07-14T20:14:06Z") }}
  • 44
  • 7