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