Logging Best Practices for SailPoint Implementations
SailPoint recommends using log4j for all logging operations. Although some legacy code uses Apache Commons Logging, log4j is the preferred and more efficient approach. Commons Logging ultimately delegates to log4j, creating an unnecessary abstraction layer.
Recommended Logger Construction (log4j)
import org.apache.log4j.Logger;
Logger alog = Logger.getLogger("com.sailpoint.class.module");
Not Recommended (Commons Logging)
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Log alog = LogFactory.getLog("com.sailpoint.class.module");
Using Commons Logging works, but it introduces avoidable complexity. Additionally, logger objects defined outside a method cannot mix classes without causing conflicts.
Importance of Proper Logging
Logging is essential in web applications because traditional debugging tools cannot pause execution or inspect runtime variables. Effective logging provides visibility into application behavior and accelerates troubleshooting.
A common anti-pattern is using vague statements such as:
log.error("I am here");
log.error("Now I am here");
This approach is ineffective because:
- Use of an out-of-the-box logger instance
- Incorrect use of the
errorlevel for basic debugging - No indication of program location or context
- No meaningful information in the log output
Best Practices
1. Always Create a Dedicated Logger
Never rely on the default log object. Create your own logger instance. Avoid naming it
log.
2. Use Log Levels Correctly
Understanding log levels is critical:
- TRACE — Highly verbose; use only in tight loops or deep logic analysis
- DEBUG — Primary level for development and troubleshooting
- INFO — Suitable for method-entry statements
- WARN — Use for non-fatal issues that should appear in production logs
- ERROR — Use in catch blocks or severe failures
Configure levels in log4j2.properties (or log4j.properties for older versions).
3. Use Structured Prefixes (“Tags”)
Each log entry should include a standardized prefix identifying the client, module code, and a unique number.
String fileNumber = (String) object.getAttribute("FILENUMBER");
alog.debug("ACM-WDC-001 Entered WorkDay Customization rule for user " + fileNumber);
4. Provide Meaningful Log Content
Avoid empty statements like "I am here". Include relevant data and null-check before printing. This
improves SIEM analysis and accelerates root-cause identification.
Update 2026 — Avoid Logging Wrapper Methods
Some implementations introduce wrapper methods such as:
void logx(Logger xlog, String level, String message) {
if ("debug".equals(level)) xlog.debug(message);
else if ("info".equals(level)) xlog.info(message);
else if ("trace".equals(level)) xlog.trace(message);
else if ("warn".equals(level)) xlog.warn(message);
else if ("error".equals(level)) xlog.error(message);
}
This pattern defeats log4j’s built-in level filtering. For example:
logx(xlogger, "debug", plan.toXml());
Even if the log level is set to WARN, the system still evaluates
plan.toXml(), causing unnecessary overhead.
Correct Approach
if (alog.isDebugEnabled()) {
alog.debug("ACM-WDC-100 The provisioning plan is " + plan.toXml());
}
Use isDebugEnabled() and isTraceEnabled() for DEBUG and
TRACE statements that require object evaluation. These checks are generally not required for
INFO, WARN, or ERROR. They are also not required when the
text being printed does not need evaluation, such as printing Strings or numbers.
Logging Errors
Use WARN when the issue is important enough to appear in production logs but does not stop execution. Inside catch blocks use error. Below is a way to print the class and message for a general exception.
catch (Exception ex) {
alog.error("ACM-WDC-901 Error evaluating expression: " + ex.getClass().getName() + ":" + ex.getMessage());
}
TLDR : Logging Best Practices
- Always use log4j classes and methods.
- Do not name your logger
log. - Define loggers inside method bodies.
-
Enclose the main body of every rule in
{ }to ensure proper garbage collection. Anything defined outside is effectively global; useCustomGlobalfor truly global objects. - Tag each log line with a structured prefix.
- Use
isDebugEnabled() or isTraceEnabled()for DEBUG/TRACE and never wrap log calls in custom logging methods.
No comments:
Post a Comment