Skip to content

Logging

SØAD uses SLF4J as the logging API, with Log4j 2 as the underlying implementation. This setup provides flexible, high-performance logging for transactions, models, and other framework components.

Logging is essential for diagnosing issues, auditing activity, and understanding application behavior—especially in production environments or when running inside containers.


Using Logging in Transactions

Within your Jython Transactions, you can use the Log class to write log entries. Supported levels include info, debug, warn, and error. These methods integrate seamlessly with SLF4J and Log4j’s configuration.

Example: Using Logging in a Transaction

from sufia.util import Log

class Example(Layout):
    def view(self, ctx):
        Log.info(ctx, "Example view called.")
        Log.debug(ctx, "Request parameters: %s" % ctx.getAllParameters())

        try:
            # Transaction logic
            Log.info(ctx, "Processing completed successfully.")
        except Exception as e:
            Log.error(ctx, "Error occurred: %s" % str(e))
            raise e
Method Usage
Log.print(ctx, string) For general informational messages.
Log.info(ctx, string) For general informational messages.
Log.debug(ctx, string) For detailed debugging output (helpful during development).
Log.trace(ctx, string) For tracing detailed information.
Log.warn(ctx, string) For warning messages.
Log.error(ctx, string, exception) For capturing unexpected exceptions or failures.

Logging in Container Environments

Did You Know?

If SØAD is running in a containerized environment, the standard print() output may not appear in the IDE. Instead, always use Log.info(), Log.debug(), or Log.print(), which are routed through SLF4J and work reliably inside containers.


Using SLF4J Logger Directly

While SØAD provides the Log utility for simplicity, you can also create your own SLF4J Logger instances if you need class-specific loggers, advanced features, or consistent Java logging practices.

Example: SLF4J Logger in a Transaction

from org.slf4j import LoggerFactory

class Orders(object):
    # Create a class-specific logger instance
    logger = LoggerFactory.getLogger("OrdersTransaction")

    def view(self, ctx):
        request = ctx.getRequest()
        Orders.logger.info("Orders view accessed.")
        Orders.logger.debug("Request parameters: %s" % request.getParameterMap())

        try:
            # Transaction logic here
            Orders.logger.info("Order listing completed successfully.")
        except Exception as e:
            Orders.logger.error("Failed to process orders: %s" % str(e))
            raise e

This pattern is for developers familiar with enterprise Java, or when you need finer control over logging granularity.


Default Log4j Configuration

Below is the default log4j2.properties included with SØAD. This configuration outputs logs both to the console and to rolling log files saved under ${SUFIA_HOME}/logs/.

# Appenders
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%T] %-5level %c{1} - %msg%n

appender.rolling.type = RollingFile
appender.rolling.name = LOGFILE
appender.rolling.fileName = ${env:SUFIA_HOME}/logs/soad.log
appender.rolling.filePattern = ${env:SUFIA_HOME}/logs/soad-%d{yyyy-MM-dd}.log
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%T] %-5level %c{1} - %msg%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 30

# Root Logger
rootLogger.level = INFO
rootLogger.appenderRef.rolling.ref = LOGFILE
rootLogger.appenderRef.console.ref = STDOUT

# keep activejdbc logs at minimum
logger.activejdbc.name = org.javalite.activejdbc
logger.activejdbc.level = WARN