Server-side scripts have only log.info() (goes to SystemOut.log). For your own log file per process app or per instance, use a small Java integration with Log4j (or java.util.logging) in a managed jar and keep the logger name / file per app:
// Java (log4j 2): one logger per process app, file per app; called from a Java Integration "Log"
public class AppLogger {
private static final java.util.concurrent.ConcurrentHashMap<String, Logger> LOGGERS = new java.util.concurrent.ConcurrentHashMap<>();
public static void log(String app, String level, String piid, String message) {
Logger l = LOGGERS.computeIfAbsent(app, AppLogger::create);
String line = "[" + piid + "] " + message;
switch (level) { case "ERROR": l.error(line); break; case "WARN": l.warn(line); break; case "DEBUG": l.debug(line); break; default: l.info(line); }
}
private static Logger create(String app) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration cfg = ctx.getConfiguration();
String dir = System.getProperty("bpm.app.log.dir", "/var/log/bpm");
Appender ap = RollingFileAppender.newBuilder().setName("app-" + app).withFileName(dir + "/" + app + ".log")
.withFilePattern(dir + "/" + app + "-%d{yyyy-MM-dd}.log.gz").withPolicy(TimeBasedTriggeringPolicy.newBuilder().build())
.setLayout(PatternLayout.newBuilder().withPattern("%d %-5p %m%n").build()).setConfiguration(cfg).build();
ap.start(); cfg.addAppender(ap);
LoggerConfig lc = new LoggerConfig("bpm.app." + app, Level.DEBUG, false); lc.addAppender(ap, null, null);
cfg.addLogger("bpm.app." + app, lc); ctx.updateLoggers(); return ctx.getLogger("bpm.app." + app);
}
}// toolkit service flow "Log" (inputs level, message) - script before the Java step
tw.local.app = tw.system.model.processApp.acronym;
tw.local.piid = tw.system.currentProcessInstanceID != null ? tw.system.currentProcessInstanceID : "-";
// Java Integration: AppLogger.log(app, level, piid, message)
Notes: the log directory must exist on every cluster member (or use a shared NFS path); rotate with the time-based policy; put the toolkit service in every app so that the call is one step (Log with level + message); never log full business objects with personal data; on CP4BA write to stdout instead (the platform collects it) - log.info("[" + app + "][" + piid + "] " + message) with a structured prefix is enough for the log stack to filter per app. Also see question 107 for the other logging options.
References