On Thu, 2017-09-14 at 01:15 +0000, John Logan wrote:
> I got this working and thought I'd follow up with what I did in case
> anyone else needs this sort of thing.
Looks interesting, thanks for sharing.
Robert
>
>
> I used SiftingAppender pretty much as shown in any of the examples
> one can find online. I put the following logback.xml in my
> sling.home, and pointed the OSGI configuration variable
> org.apache.sling.commons.log.configurationFile to it:
>
>
> <configuration>
> <appender name="SIFT"
> class="ch.qos.logback.classic.sift.SiftingAppender">
> <discriminator>
> <key>jobId</key>
> <defaultValue>/var/log/sling/error.log</defaultValue>
> </discriminator>
> <sift>
> <appender name="FILE-${jobId}"
> class="ch.qos.logback.core.FileAppender">
> <file>${logPath}</file>
> <layout class="ch.qos.logback.classic.PatternLayout">
> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -
> %msg%n</pattern>
> </layout>
> </appender>
> </sift>
> </appender>
>
> <root level="info">
> <appender-ref ref="SIFT" />
> </root>
> </configuration>
>
>
> An abstract wrapper implementation of JobExecutor sets up the MDC to
> conform to what's expected in the logback.xml, and provides a few
> other niceties. Replace the SlingResourceProvider/StorageNode stuff
> with whatever you use to access files and Sling nodes; it's just a
> simple abstraction layer that we happen to be using.
>
>
> package com.xyz.content.sling.processor;
>
> import java.io.BufferedReader;
> import java.io.IOException;
> import java.nio.charset.StandardCharsets;
> import java.nio.file.Files;
> import java.nio.file.Path;
> import java.nio.file.Paths;
>
> import org.apache.sling.api.resource.LoginException;
> import org.apache.sling.api.resource.ResourceResolver;
> import org.apache.sling.api.resource.ResourceResolverFactory;
> import org.apache.sling.event.jobs.Job;
> import org.apache.sling.event.jobs.consumer.JobExecutionContext;
> import org.apache.sling.event.jobs.consumer.JobExecutionResult;
> import org.apache.sling.event.jobs.consumer.JobExecutor;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> import org.slf4j.MDC;
>
> import com.xyz.content.sling.storage.SlingResourceProvider;
> import com.xyz.storage.StorageNode;
>
> /**
> * Sling job executor with build job logging.
> *
> * This class wraps build processing with job-specific log
> management.
> * Job submitters need to configure the following job properties
> * prior to submitting a job:
> * * jobId - A symbolic identifier for the job. This value must be
> * unique throughout the life of the job. Subclasses
> * may use this value as a job name for submitting
> * and monitoring SLURM jobs.
> * * logPath - The pathname to the build log file.
> * * damLogPath - If specified, the DAM resource to which
> * the log output should be copied upon build
> completion.
> * * clearLog - An option boolean parameter which, when true,
> * removes the build log file if it exists prior
> * to commencing the build.
> *
> * @author john
> *
> */
> public abstract class BuildJobExecutor implements JobExecutor {
> private static Logger LOG =
> LoggerFactory.getLogger(BuildJobExecutor.class);
>
> /**
> * Retrieve a resource resolver factory for build processing.
> *
> * @return the resource resolver factory
> */
> protected abstract ResourceResolverFactory getResolverFactory();
>
> /**
> * Subclass-specific build processing method.
> *
> * @param job
> * @param context
> * @param resolver
> * @return the result of build processing
> */
> protected abstract JobExecutionResult build(Job job,
> JobExecutionContext context, ResourceResolver resolver);
>
> @Override
> public JobExecutionResult process(Job job, JobExecutionContext
> context) {
> //
> // Prepare for the log directory and file.
> //
> final String jobId = job.getProperty("jobId", String.class);
> final Path logPath = Paths.get(job.getProperty("logPath",
> String.class));
> final Path logParentPath = logPath.getParent();
> if (logParentPath != null) {
> try {
> Files.createDirectories(logParentPath);
> }
> catch (final IOException e) {
> return handleError(context, "Unable to create log
> directory " + logParentPath);
> }
> }
>
> if (Boolean.TRUE.equals(job.getProperty("resetLog"))) {
> try {
> Files.deleteIfExists(logPath);
> }
> catch (final IOException e) {
> return handleError(context, "Unable to clear log file
> " + logPath);
> }
> }
>
> LOG.info("Starting build job with ID " + jobId);
> ResourceResolver resolver;
> try {
> resolver =
> getResolverFactory().getServiceResourceResolver(null);
> }
> catch (final LoginException e) {
> return handleError(context, "Unable get build job
> resource resolver, check cbservice user configuration.");
> }
>
> //
> // Perform the build operation. Logging to the job-specific
> log file starts here.
> //
> MDC.put("jobId", jobId);
> MDC.put("logPath", logPath.toString());
> try {
> final JobExecutionResult result = build(job, context,
> resolver);
> if (job.getProperty("damLogPath") != null) {
> final Path damLogPath =
> Paths.get(job.getProperty("damLogPath", String.class));
> saveLog(resolver, logPath, damLogPath);
> }
> return result;
> }
> catch (final Throwable e) {
> LOG.error("Build job failed with an exception.", e);
> return handleError(context, "Build job failed with an
> exception: " + e.getMessage());
> }
> finally {
> MDC.remove("jobId");
> MDC.remove("logPath");
> resolver.close();
> }
> }
>
> private JobExecutionResult handleError(JobExecutionContext
> context, String message) {
> LOG.error(message);
> return context.result().message(message).cancelled();
> }
>
> private void saveLog(ResourceResolver resolver, Path logPath,
> Path damLogPath) {
> try (BufferedReader reader = Files.newBufferedReader(logPath,
> StandardCharsets.UTF_8)) {
> final SlingResourceProvider storageProvider = new
> SlingResourceProvider();
> storageProvider.setResolver(resolver);
> final StorageNode damLogNode =
> storageProvider.get(damLogPath);
> damLogNode.copyFromReader(reader,
> StandardCharsets.UTF_8);
> resolver.commit();
> }
> catch (final IOException e) {
> LOG.error("Unable to move build log " + logPath + " to
> DAM resource " + damLogPath, e);
> }
> }
> }
>
>
>
> ________________________________
> From: Robert Munteanu <[email protected]>
> Sent: Friday, September 8, 2017 1:13:02 AM
> To: [email protected]
> Subject: Re: Directing Sling job logging output to separate files?
>
> Hi John,
>
> On Fri, 2017-09-08 at 05:28 +0000, John Logan wrote:
> > Hi,
> >
> >
> > I'm using the Sling job manager to handle some long running tasks,
> > and would like to direct the log output for each job to its own
> > file
> > at a job-specific path. Is there a straightforward way to achieve
> > this?
>
> If your jobs use separate loggers, you can achieve that either by:
>
> - manually creating loggers and appenders via http://localhost:8080/s
> ys
> tem/console/slinglog/
> - adding specific loggers/appenders to the provisioning model
>
> There might be a way of adding those at runtime using the logback
> APIs,
> but I haven't tried it before.
>
> Robert