coldbox-logging

Use this skill for all ColdBox-specific logging concerns: configuring LogBox inside a ColdBox application (config/LogBox.cfc, inline DSL, configFile pointer), per-environment log levels, injecting loggers into handlers/interceptors/services via the WireBox logbox DSL, accessing logbox from the ColdBox proxy, and logging best practices specific to the ColdBox lifecycle.

ColdBox Logging Skill

When to Use This Skill

Load this skill when:

  • Configuring LogBox inside a ColdBox application
  • Choosing between config/LogBox.cfc, inline logbox DSL, or a configFile pointer
  • Setting per-environment log levels (development vs production) in ColdBox.cfc
  • Injecting loggers into handlers, interceptors, services, or models
  • Accessing LogBox from a ColdBox proxy
  • Combining LogBox with ColdBox lifecycle events (interceptors, error handling)

For standalone LogBox concepts (appenders, layouts, custom appenders), load the logbox skill.

Language Mode Reference

ConceptBoxLang (.bx)CFML (.cfc)
Class declarationclass [extends="..."] {component [extends="..."] {
DI annotation@inject above propertyproperty name="x" inject="y";
Handler baseextends="coldbox.system.EventHandler"same
Interceptor baseextends="coldbox.system.Interceptor"same

How ColdBox Loads LogBox

ColdBox resolves your LogBox configuration in this order:

  1. Is there a logbox variable in config/ColdBox.cfc configure()?
    • No → Does config/LogBox.cfc exist? Yes → use it by convention. No → use ColdBox framework defaults.
    • Yes → Does it have a configFile key? Yes → load that CFC. No → treat the struct as inline DSL.

Default ColdBox configuration (if you define nothing):

logBox = {
    appenders : {
        console : { class : "coldbox.system.logging.appenders.DummyAppender" }
    },
    root : { levelMax : "OFF", levelMin : "OFF", appenders : "*" }
}

All logging is OFF by default. You must configure it yourself.

Configuration Methods

Method 1 — config/LogBox.cfc (recommended for large apps)

// config/LogBox.cfc — BoxLang
class extends="coldbox.system.logging.config.LogBoxConfig" {

    function configure() {

        appenders = {
            console : {
                class    : "coldbox.system.logging.appenders.ConsoleAppender",
                levelMin : "DEBUG",
                levelMax : "FATAL"
            },
            rolling : {
                class      : "coldbox.system.logging.appenders.RollingFileAppender",
                levelMin   : "WARN",
                levelMax   : "FATAL",
                properties : {
                    filePath        : "#getDirectoryFromPath( getBaseTemplatePath() )#logs",
                    fileName        : "app",
                    fileMaxSize     : 5000,
                    fileMaxArchives : 5
                }
            }
        }

        // Production default: WARN and above to file
        root = { levelMin : "WARN", levelMax : "FATAL", appenders : "rolling" }

        categories = {
            "coldbox.system" : { levelMin : "WARN", levelMax : "FATAL", appenders : "rolling" },
            "handlers"       : { levelMin : "INFO", levelMax : "FATAL", appenders : "console,rolling" },
            "models"         : { levelMin : "DEBUG", levelMax : "FATAL", appenders : "console" }
        }

        // Silence verbose packages
        off = [ "coldbox.system.plugins.BeanFactory" ]
    }
}
// CFML
component extends="coldbox.system.logging.config.LogBoxConfig" {

    function configure() {

        appenders = {
            console : {
                class    : "coldbox.system.logging.appenders.ConsoleAppender",
                levelMin : "DEBUG",
                levelMax : "FATAL"
            },
            rolling : {
                class      : "coldbox.system.logging.appenders.RollingFileAppender",
                levelMin   : "WARN",
                levelMax   : "FATAL",
                properties : {
                    filePath        : "#getDirectoryFromPath( getBaseTemplatePath() )#logs",
                    fileName        : "app",
                    fileMaxSize     : 5000,
                    fileMaxArchives : 5
                }
            }
        }

        root       = { levelMin : "WARN", levelMax : "FATAL", appenders : "rolling" }
        categories = {
            "handlers" : { levelMin : "INFO", levelMax : "FATAL", appenders : "console,rolling" },
            "models"   : { levelMin : "DEBUG", levelMax : "FATAL", appenders : "console" }
        }
    }
}

Method 2 — Inline DSL in config/ColdBox.cfc

// Inside configure()
logbox = {
    appenders : {
        console : {
            class    : "coldbox.system.logging.appenders.ConsoleAppender",
            levelMin : "DEBUG",
            levelMax : "FATAL"
        },
        rolling : {
            class      : "coldbox.system.logging.appenders.RollingFileAppender",
            levelMin   : "WARN",
            levelMax   : "FATAL",
            properties : {
                filePath        : "#getDirectoryFromPath( getBaseTemplatePath() )#logs",
                fileName        : "app",
                fileMaxSize     : 5000,
                fileMaxArchives : 5
            }
        }
    },
    root       : { levelMin : "WARN", levelMax : "FATAL", appenders : "rolling" },
    categories : {
        "handlers" : { levelMin : "INFO", levelMax : "FATAL", appenders : "console,rolling" },
        "models"   : { levelMin : "DEBUG", levelMax : "FATAL", appenders : "console" }
    }
}

Method 3 — External CFC Pointer

// In config/ColdBox.cfc configure()
logbox = { configFile : "config.LogBox" }

// Or with a full dotted path
logbox = { configFile : "myapp.config.LogBoxProduction" }

Per-Environment Log Levels

Override the logbox variable inside environment methods. The environment methods run after configure() and merge/override settings.

// config/ColdBox.cfc

function configure() {
    // Shared appender definitions
    logbox = {
        appenders : {
            console : {
                class    : "coldbox.system.logging.appenders.ConsoleAppender",
                levelMin : "DEBUG",
                levelMax : "FATAL"
            },
            rolling : {
                class      : "coldbox.system.logging.appenders.RollingFileAppender",
                levelMin   : "ERROR",
                levelMax   : "FATAL",
                properties : {
                    filePath        : "#getDirectoryFromPath( getBaseTemplatePath() )#logs",
                    fileName        : "app",
                    fileMaxSize     : 5000,
                    fileMaxArchives : 5
                }
            },
            emailAlert : {
                class      : "coldbox.system.logging.appenders.EmailAppender",
                levelMin   : "FATAL",
                levelMax   : "FATAL",
                properties : {
                    from    : "[email protected]",
                    to      : "[email protected]",
                    subject : "[PROD FATAL] Application Error"
                }
            }
        },
        // Default: production-safe
        root       : { levelMin : "ERROR", levelMax : "FATAL", appenders : "rolling" },
        categories : {}
    }
}

// Development: log everything to console only
function development() {
    logbox.root = { levelMin : "DEBUG", levelMax : "FATAL", appenders : "console" }
    logbox.categories[ "coldbox.system" ] = { levelMin : "WARN", levelMax : "FATAL", appenders : "console" }
}

// Staging: INFO+ to console and file, no email alerts
function staging() {
    logbox.root = { levelMin : "INFO", levelMax : "FATAL", appenders : "console,rolling" }
}

// Production: WARN+ to file, FATAL emails ops
function production() {
    logbox.root = { levelMin : "WARN", levelMax : "FATAL", appenders : "rolling,emailAlert" }
}

WireBox Injection DSL

Inject loggers into any WireBox-managed component. The logbox: DSL prefix is always available inside ColdBox.

DSL TokenReturns
logboxThe application LogBox instance
logbox:rootThe root logger
logbox:logger:{this}Logger whose category = current class path (most common)
logbox:logger:category.nameLogger for a specific named category

Handlers

// BoxLang handler
class extends="coldbox.system.EventHandler" {

    @inject( "logbox:logger:{this}" )
    property name="log";

    function index( event, rc, prc ) {
        log.info( "Rendering index, user=##rc.userId" )

        try {
            prc.data = userService.listActive()
        } catch( any e ) {
            log.error( "Failed to load users", e )
            event.setHTTPHeader( statusCode : 500 )
            return "error"
        }
    }
}
// CFML handler
component extends="coldbox.system.EventHandler" {

    property name="log" inject="logbox:logger:{this}";

    function index( event, rc, prc ) {
        log.info( "Rendering index, user=##rc.userId" )

        try {
            prc.data = userService.listActive()
        } catch( any e ) {
            log.error( "Failed to load users", e )
            event.setHTTPHeader( statusCode : 500 )
            return "error"
        }
    }
}

Interceptors

// BoxLang interceptor
class extends="coldbox.system.Interceptor" {

    @inject( "logbox:logger:{this}" )
    property name="log";

    function preProcess( event, interceptData, rc, prc ) {
        if( log.canDebug() ) {
            log.debug( "Incoming request: ##event.getCurrentRoutedURL()", {
                method : event.getHTTPMethod(),
                user   : prc.oCurrentUser?.getId() ?: "anonymous"
            } )
        }
    }

    function onException( event, interceptData, rc, prc ) {
        log.error(
            "Unhandled exception on ##event.getCurrentEvent()",
            {
                type    : interceptData.exception.type,
                message : interceptData.exception.message,
                detail  : interceptData.exception.detail
            }
        )
    }
}
// CFML interceptor
component extends="coldbox.system.Interceptor" {

    property name="log" inject="logbox:logger:{this}";

    function preProcess( event, interceptData, rc, prc ) {
        if( log.canDebug() ) {
            log.debug( "Incoming request: ##event.getCurrentRoutedURL()" )
        }
    }

    function onException( event, interceptData, rc, prc ) {
        log.error( "Unhandled exception", interceptData.exception )
    }
}

Models / Services

class PaymentService {

    @inject( "logbox:logger:{this}" )
    property name="log";

    function charge( required order ) {
        log.info( "Charging order ##order.getId()", { amount : order.getTotal() } )

        try {
            var result = gateway.process( order )
            log.info( "Charge successful", { transactionId : result.id } )
            return result
        } catch( GatewayException e ) {
            log.error( "Gateway error on order ##order.getId()", {
                error   : e.message,
                code    : e.errorCode,
                orderId : order.getId()
            } )
            rethrow
        }
    }
}
component {

    property name="log" inject="logbox:logger:{this}";

    function charge( required order ) {
        log.info( "Charging order ##order.getId()", { amount : order.getTotal() } )

        try {
            var result = gateway.process( order )
            log.info( "Charge successful", { transactionId : result.id } )
            return result
        } catch( GatewayException e ) {
            log.error( "Gateway error on order ##order.getId()", e )
            rethrow
        }
    }
}

Accessing LogBox Programmatically

Inside any ColdBox component you can reach LogBox through the controller:

// Inside a handler or interceptor (has access to the controller)
var logbox = controller.getLogBox()
var log    = logbox.getLogger( this )

// Inside application.cfc after bootstrap
var logbox = application.cbController.getLogBox()

LogBox from the ColdBox Proxy

When calling ColdBox from a non-ColdBox context (Flex, REST, legacy pages):

// In your ColdBox Proxy
component extends="coldbox.system.remote.ColdboxProxy" {

    function processPayment( required amount ) {
        var log = getLogBox().getLogger( this )
        log.info( "Proxy payment request", { amount : arguments.amount } )

        try {
            return process( event="api.payments.process", collection={ amount : arguments.amount } )
        } catch( any e ) {
            log.error( "Proxy payment failed", e )
            rethrow
        }
    }
}

Logging in ColdBox Error Handling

Use an onException interceptor (preferred over onError in Application.cfc) for centralized error logging:

// interceptors/GlobalExceptionLogger.bx
class extends="coldbox.system.Interceptor" {

    @inject( "logbox:logger:{this}" )
    property name="log";

    function onException( event, interceptData, rc, prc ) {
        var exception = interceptData.exception

        log.error(
            "Unhandled exception [##exception.type##]: ##exception.message##",
            {
                type       : exception.type,
                message    : exception.message,
                detail     : exception.detail,
                stackTrace : exception.stackTrace ?: "",
                event      : event.getCurrentEvent(),
                url        : event.getCurrentRoutedURL()
            }
        )
    }
}

Register in config/ColdBox.cfc:

interceptors = [
    { class : "interceptors.GlobalExceptionLogger", name : "GlobalExceptionLogger" }
]

Category Naming Conventions in ColdBox

Always use dot-notation that mirrors your component path. This enables category inheritance — configuring a parent category covers all children.

Component PathRecommended Logger Injection
handlers.UserHandlerlogbox:logger:{this} → category handlers.UserHandler
models.services.PaymentServicelogbox:logger:{this} → category models.services.PaymentService
interceptors.SecurityInterceptorlogbox:logger:{this} → category interceptors.SecurityInterceptor
modules.myModule.models.Repologbox:logger:{this} → category modules.myModule.models.Repo

Configure once at the package level to cover all descendants:

categories = {
    // All handlers — INFO and above
    "handlers"   : { levelMin : "INFO", levelMax : "FATAL", appenders : "console,rolling" },
    // All models — DEBUG in dev (overridden per environment)
    "models"     : { levelMin : "DEBUG", levelMax : "FATAL", appenders : "console" },
    // All interceptors — INFO and above
    "interceptors" : { levelMin : "INFO", levelMax : "FATAL", appenders : "rolling" }
}

Performance Patterns

Always guard expensive debug messages

// Bad — serialization always happens
log.debug( "Request context: #serializeJSON( rc )#" )

// Good — only evaluated when DEBUG is enabled
if( log.canDebug() ) {
    log.debug( "Request context: #serializeJSON( rc )#" )
}

// Best — closure avoids the if statement
log.debug( () => "Request context: #serializeJSON( rc )#" )

Avoid logging entire request/response objects in production

// Bad — may log sensitive headers, tokens, PII
log.debug( "Request", getHTTPRequestData() )

// Good — log only what you need, explicitly
log.debug( "Request", {
    method : event.getHTTPMethod(),
    route  : event.getCurrentRoutedURL(),
    userId : prc.currentUser?.getId() ?: "anon"
} )

ColdBox Logging Best Practices

  • Use config/LogBox.cfc for complex configurations; inline DSL for simple or environment-only overrides
  • Per-environment overrides belong in development() / staging() / production() methods in ColdBox.cfc
  • Inject logbox:logger:{this} in every handler, service, and interceptor — the category auto-matches the class path
  • Never use writeOutput() or cflog for application logging — route everything through LogBox for consistency, filtering, and format control
  • Production minimum: WARN — only warnings and above to rolling file; FATAL to email
  • Development maximum: DEBUG to console — no file I/O overhead; instant feedback
  • Log security events at INFO or WARN: login attempts, permission denials, suspicious inputs
  • Log business events at INFO: order placed, payment processed, account created
  • Log integrations at DEBUG: external API calls, response codes, latency
  • Always include context in extraInfo (user ID, order ID, relevant IDs) — makes log searching dramatically faster
  • Register a global onException interceptor for centralized error capture instead of scattered try/catch logging