boxlang-core-dev-logging
BoxLang Logging
Overview
BoxLang uses a centralized logging system built on Logback (SLF4J implementation).
All logging MUST go through LoggingService — never use System.out.println() or
create SLF4J Logger instances directly.
Key classes:
ortus.boxlang.runtime.logging.LoggingService— singleton service managing all loggersortus.boxlang.runtime.logging.BoxLangLogger— wrapper around SLF4JLocationAwareLogger
Getting a Logger
Pre-Configured Common Loggers
import ortus.boxlang.runtime.logging.BoxLangLogger;
import ortus.boxlang.runtime.services.LoggingService;
LoggingService loggingService = BoxRuntime.getInstance().getLoggingService();
// Common loggers — already initialized, ready to use
BoxLangLogger logger = loggingService.RUNTIME_LOGGER; // Core runtime events
BoxLangLogger logger = loggingService.ASYNC_LOGGER; // Async operations
BoxLangLogger logger = loggingService.CACHE_LOGGER; // Cache operations
BoxLangLogger logger = loggingService.EXCEPTION_LOGGER; // Exception tracking
BoxLangLogger logger = loggingService.DATASOURCE_LOGGER; // Database operations
BoxLangLogger logger = loggingService.MODULES_LOGGER; // Module loading/lifecycle
BoxLangLogger logger = loggingService.SCHEDULER_LOGGER; // Scheduled tasks
BoxLangLogger logger = loggingService.APPLICATION_LOGGER;// Application-level events
Creating Named Loggers
LoggingService loggingService = BoxRuntime.getInstance().getLoggingService();
// Named logger (logs to logs/myfeature.log)
BoxLangLogger logger = loggingService.getLogger( "myfeature" );
// Relative path (relative to configured logs directory)
BoxLangLogger logger = loggingService.getLogger( "subsystem/component" );
// Absolute path
BoxLangLogger logger = loggingService.getLogger( "/var/log/boxlang/custom.log" );
getLogger() automatically appends .log if no extension is present, creates the
logger lazily, and caches it for reuse (case-insensitive).
From Context
// Any IBoxContext provides a logger
BoxLangLogger logger = context.getLogger();
// From BaseInterceptor subclass
BoxLangLogger logger = this.getLogger();
// From BaseScheduler subclass
BoxLangLogger logger = this.getLogger();
Logging Methods
logger.trace( "Entering method with params: {}", params ); // Very detailed
logger.debug( "Processing {} items in batch", items.size() ); // Debug info
logger.info( "Server started on port {}", port ); // Key events
logger.warn( "Cache threshold exceeded: {} of {}", size, max ); // Warnings
logger.error( "Connection failed: {}", e.getMessage() ); // Errors
logger.error( "Unexpected exception", e ); // With stack trace
Key Practices
Always Use Parameterized Messages
// CORRECT — message built only when level is enabled
logger.debug( "User {} logged in from {}", username, ipAddress );
// WRONG — concatenation happens regardless of log level
logger.debug( "User " + username + " logged in from " + ipAddress );
Include Exceptions When Logging Errors
try {
processRequest( context );
} catch ( Exception e ) {
logger.error( "Failed to process request for {}", requestPath, e );
}
Choose the Right Logger
| Logger | Use for |
|---|---|
RUNTIME_LOGGER |
Core runtime events, service start/stop |
MODULES_LOGGER |
Module loading, registration, unloading |
ASYNC_LOGGER |
Thread pools, futures, async work |
SCHEDULER_LOGGER |
Scheduled tasks, cron jobs |
CACHE_LOGGER |
Cache hits, misses, eviction |
DATASOURCE_LOGGER |
Query execution, connection management |
EXCEPTION_LOGGER |
Caught exceptions for audit/analysis |
APPLICATION_LOGGER |
Application lifecycle events |
| Named logger | New features or subsystems needing isolation |
Logging in Common Patterns
Service Initialization
public class MyService extends BaseService {
private BoxLangLogger logger;
@Override
public void onStartup() {
this.logger = BoxRuntime.getInstance().getLoggingService().getLogger( "myservice" );
logger.info( "MyService starting up..." );
}
@Override
public void onShutdown( Boolean force ) {
logger.info( "MyService shutting down (force={})", force );
}
}
BIF with Logging
@BoxBIF
public class MyBIF extends BIF {
private static final BoxLangLogger logger =
BoxRuntime.getInstance().getLoggingService().getLogger( "bifs.mybif" );
@Override
public Object invoke( IBoxContext context, ArgumentsScope arguments ) {
String input = arguments.getAsString( Key.of( "input" ) );
logger.debug( "Processing input of length {}", input.length() );
try {
Object result = doWork( input );
logger.trace( "Result computed successfully" );
return result;
} catch ( Exception e ) {
logger.error( "BIF processing failed for input: {}", input, e );
throw new BoxRuntimeException( "Processing error: " + e.getMessage(), e );
}
}
}
Interceptor with Logging
@Interceptor
public class AuditInterceptor extends BaseInterceptor {
@Override
public void configure() {
// this.log is automatically injected by BaseInterceptor
this.log.info( "AuditInterceptor configured" );
}
@InterceptionPoint
public void onRequestStart( IStruct event ) {
this.log.info( "Request started: {}", event.getAsString( Key.of("path") ) );
}
}
Scheduler with Logging
public class MyScheduler extends BaseScheduler {
public MyScheduler() {
super( "my-scheduler" );
// this.logger is available in BaseScheduler
}
@Override
public void configure() {
task( "cleanupTask" )
.call( () -> {
this.logger.info( "Running cleanup task" );
performCleanup();
})
.everyHour();
}
}
ModuleConfig.bx (BoxLang)
// ModuleConfig.bx — log is auto-injected
class {
function onLoad() {
// log is already available — no setup needed
log.info( "Module loaded. API URL: #settings.baseUrl#" )
}
function configure() {
log.debug( "Configuring module with apiKey length: #len(settings.apiKey)#" )
}
function onUnload() {
log.info( "Module unloaded." )
}
}
Logging Configuration (boxlang.json)
{
"logging": {
"logsDirectory": "./logs",
"level": "INFO",
"loggers": {
"scheduler": { "level": "DEBUG", "async": true },
"cache": { "level": "WARN" }
}
}
}
Supported levels (from most to least verbose): TRACE, DEBUG, INFO, WARN, ERROR
What NOT to Do
// ❌ Never use System.out / System.err
System.out.println( "My debug message" );
System.err.println( "My error" );
// ❌ Never create SLF4J loggers directly
private static final Logger log = LoggerFactory.getLogger( MyClass.class );
// ❌ Never concatenate in log calls
logger.info( "Processing " + count + " items" ); // Use {} placeholders instead
// ❌ Never log sensitive data
logger.debug( "Password: {}", user.getPassword() );
logger.trace( "Token: {}", authToken );
References
More from ortus-boxlang/skills
boxlang-functional-programming
Use this skill when working with BoxLang lambdas, closures, arrow functions, higher-order functions, functional array/struct pipelines (map, filter, reduce, flatMap, groupBy, etc.), destructuring, or spread syntax.
10boxlang-code-reviewer
Use this skill when reviewing BoxLang code for quality, correctness, security vulnerabilities, performance issues, style violations, or when providing structured code review feedback following BoxLang best practices and security guidelines.
9boxlang-best-practices
Use this skill when writing, reviewing, or improving BoxLang code to ensure it follows community best practices for naming, structure, scoping, error handling, performance, and maintainability.
9boxlang-language-fundamentals
Use this skill when writing or reviewing BoxLang code covering syntax, file types, variables, scopes, operators, control flow, exception handling, type system, and modern language features like destructuring and spread syntax.
8boxlang-security
Use this skill when reviewing BoxLang code or applications for security vulnerabilities, configuring security settings, preventing injection attacks, handling file uploads safely, managing secrets, or applying secure coding patterns drawn from OWASP Top 10 and CFML/Java security history.
8boxlang-docbox
Use this skill when generating API documentation for BoxLang or CFML projects with DocBox, including installation, CLI usage, programmatic configuration, HTML/JSON/UML/CommandBox output strategies, HTML themes, multiple sources, excludes patterns, and creating custom strategies. DocBox reads JavaDoc-style comments from your source code — see the code-documenter skill for annotation conventions.
7