agentsclimarketplace

Logging

Skill ortus-boxlang/skills/boxlang-core-development/logging

BoxLang AI skills repository and Claude Plugin

Install
npx -y skills add ortus-boxlang/skills --skill logging

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill when working with BoxLang logging: obtaining loggers via LoggingService, using BoxLangLogger (trace/debug/info/warn/error), pre-configured common loggers, creating named loggers, parameterized messages, accessing loggers from context and interceptors, and logging configuration in boxlang.json.

SKILL.md

7.9 KB, as published. Nobody here has run it

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 loggers
  • ortus.boxlang.runtime.logging.BoxLangLogger — wrapper around SLF4J LocationAwareLogger

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

LoggerUse for
RUNTIME_LOGGERCore runtime events, service start/stop
MODULES_LOGGERModule loading, registration, unloading
ASYNC_LOGGERThread pools, futures, async work
SCHEDULER_LOGGERScheduled tasks, cron jobs
CACHE_LOGGERCache hits, misses, eviction
DATASOURCE_LOGGERQuery execution, connection management
EXCEPTION_LOGGERCaught exceptions for audit/analysis
APPLICATION_LOGGERApplication lifecycle events
Named loggerNew 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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.