boxlang-core-dev-logging — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited boxlang-core-dev-logging (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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 SLF4J LocationAwareLoggerimport 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 eventsLoggingService 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).
// Any IBoxContext provides a logger
BoxLangLogger logger = context.getLogger();
// From BaseInterceptor subclass
BoxLangLogger logger = this.getLogger();
// From BaseScheduler subclass
BoxLangLogger logger = this.getLogger();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// 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 );try {
processRequest( context );
} catch ( Exception e ) {
logger.error( "Failed to process request for {}", requestPath, e );
}| 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 |
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 );
}
}@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
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") ) );
}
}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 — 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." )
}
}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
// ❌ 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 );~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.