org.ow2.proactive.scheduler.task.TaskLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive.scheduler.task.TaskLogger.java

Source

/*
 * ProActive Parallel Suite(TM):
 * The Open Source library for parallel and distributed
 * Workflows & Scheduling, Orchestration, Cloud Automation
 * and Big Data Analysis on Enterprise Grids & Clouds.
 *
 * Copyright (c) 2007 - 2017 ActiveEon
 * Contact: contact@activeeon.com
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation: version 3 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 */
package org.ow2.proactive.scheduler.task;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Appender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
import org.ow2.proactive.scheduler.common.task.Log4JTaskLogs;
import org.ow2.proactive.scheduler.common.task.TaskId;
import org.ow2.proactive.scheduler.common.task.TaskLogs;
import org.ow2.proactive.scheduler.common.util.TaskLoggerRelativePathGenerator;
import org.ow2.proactive.scheduler.common.util.logforwarder.AppenderProvider;
import org.ow2.proactive.scheduler.common.util.logforwarder.LogForwardingException;
import org.ow2.proactive.scheduler.common.util.logforwarder.appenders.AsyncAppenderWithStorage;
import org.ow2.proactive.scheduler.common.util.logforwarder.util.LoggingOutputStream;

public class TaskLogger {

    private static final Logger logger = Logger.getLogger(TaskLogger.class);

    private static final String MAX_LOG_SIZE_PROPERTY = "pas.launcher.logs.maxsize";

    // default log size, counted in number of log events
    private static final int DEFAULT_LOG_MAX_SIZE = 1024;

    private static final String FILE_APPENDER_NAME = "TASK_LOGGER_FILE_APPENDER";

    private AsyncAppenderWithStorage taskLogAppender;

    private TaskId taskId;

    private String hostname;

    private final PrintStream outputSink;

    private final PrintStream errorSink;

    private final AtomicBoolean loggersFinalized = new AtomicBoolean(false);

    private final AtomicBoolean loggersActivated = new AtomicBoolean(false);

    public TaskLogger(TaskId taskId, String hostname) {
        logger.debug("Create task logger");

        this.taskId = taskId;
        this.hostname = hostname;

        Logger taskLogger = createLog4jLogger(taskId);

        outputSink = new PrintStream(new LoggingOutputStream(taskLogger, Log4JTaskLogs.STDOUT_LEVEL), true);
        errorSink = new PrintStream(new LoggingOutputStream(taskLogger, Log4JTaskLogs.STDERR_LEVEL), true);
    }

    private Logger createLog4jLogger(TaskId taskId) {
        LogLog.setQuietMode(true); // error about log should not be logged

        Logger taskLogger = Logger
                .getLogger(Log4JTaskLogs.JOB_LOGGER_PREFIX + taskId.getJobId() + "." + taskId.value());
        taskLogger.setLevel(Log4JTaskLogs.STDOUT_LEVEL);
        taskLogger.setAdditivity(false);

        resetLogContextForImmediateService();

        taskLogger.removeAllAppenders();

        taskLogAppender = new AsyncAppenderWithStorage(getLogMaxSize(taskId));
        taskLogger.addAppender(taskLogAppender);
        return taskLogger;
    }

    private int getLogMaxSize(TaskId taskId) {
        String logMaxSizeProp = System.getProperty(MAX_LOG_SIZE_PROPERTY);
        int logMaxSize = DEFAULT_LOG_MAX_SIZE;
        if (logMaxSizeProp != null && !logMaxSizeProp.isEmpty()) {
            try {
                logMaxSize = Integer.parseInt(logMaxSizeProp);
            } catch (NumberFormatException e) {
                logger.warn(MAX_LOG_SIZE_PROPERTY
                        + " property is not correctly defined. Logs size is bounded to default value "
                        + DEFAULT_LOG_MAX_SIZE + " for task " + taskId, e);
            }
        }
        return logMaxSize;
    }

    public TaskLogs getLogs() {
        return new Log4JTaskLogs(taskLogAppender.getStorage(), this.taskId.getJobId().value());
    }

    public File createFileAppender(File pathToFolder) throws IOException {
        if (taskLogAppender.getAppender(FILE_APPENDER_NAME) != null) {
            throw new IllegalStateException("Only one file appender can be created");
        }

        File logFile = new File(pathToFolder, new TaskLoggerRelativePathGenerator(taskId).getRelativePath());

        logFile.getParentFile().mkdirs();

        FileUtils.touch(logFile);

        logFile.setWritable(true, false);

        FileAppender fap = new FileAppender(Log4JTaskLogs.getTaskLogLayout(), logFile.getAbsolutePath(), false);
        fap.setName(FILE_APPENDER_NAME);
        taskLogAppender.addAppender(fap);

        return logFile;
    }

    public PrintStream getOutputSink() {
        return outputSink;
    }

    public PrintStream getErrorSink() {
        return errorSink;
    }

    public void activateLogs(AppenderProvider logSink) {
        logger.info("Activating logs for task " + this.taskId + " (" + taskId.getReadableName() + ")");
        if (this.loggersActivated.get()) {
            logger.info("Logs for task " + this.taskId + " are already activated");
            return;
        }
        this.loggersActivated.set(true);

        // create appender
        Appender appender;
        try {
            appender = logSink.getAppender();
        } catch (LogForwardingException e) {
            logger.error("Cannot create log appender.", e);
            return;
        }
        // fill appender
        if (!this.loggersFinalized.get()) {
            taskLogAppender.addAppender(appender);
        } else {
            logger.info("Logs for task " + this.taskId + " are closed. Flushing buffer...");
            // Everything is closed: reopen and close...
            for (LoggingEvent e : taskLogAppender.getStorage()) {
                appender.doAppend(e);
            }
            appender.close();
            this.loggersActivated.set(false);
            return;
        }
        logger.info("Activated logs for task " + this.taskId);
    }

    public void getStoredLogs(AppenderProvider logSink) {
        Appender appender;
        try {
            appender = logSink.getAppender();
        } catch (LogForwardingException e) {
            logger.error("Cannot create log appender.", e);
            return;
        }
        taskLogAppender.appendStoredEvents(appender);
    }

    // need to reset MDC because calling thread is not active thread (immediate service)
    public void resetLogContextForImmediateService() {
        MDC.put(Log4JTaskLogs.MDC_JOB_ID, this.taskId.getJobId().value());
        MDC.put(Log4JTaskLogs.MDC_TASK_ID, this.taskId.value());
        MDC.put(Log4JTaskLogs.MDC_TASK_NAME, this.taskId.getReadableName());
        MDC.put(Log4JTaskLogs.MDC_HOST, hostname);
    }

    public void close() {
        synchronized (this.loggersFinalized) {
            if (!loggersFinalized.get()) {
                logger.debug("Terminating loggers for task " + this.taskId + " (" + taskId.getReadableName() + ")"
                        + "...");
                this.flushStreams();

                this.loggersFinalized.set(true);
                this.loggersActivated.set(false);

                removeTaskLogFile();

                // Unhandle loggers
                if (taskLogAppender != null) {
                    taskLogAppender.close();
                }
                logger.debug("Task logger closed");
            }
        }
    }

    private void removeTaskLogFile() {
        FileAppender fileAppender = (FileAppender) taskLogAppender.getAppender(FILE_APPENDER_NAME);
        if (fileAppender != null && fileAppender.getFile() != null) {
            FileUtils.deleteQuietly(new File(fileAppender.getFile()));
        }
    }

    private void flushStreams() {
        this.outputSink.flush();
        this.errorSink.flush();
    }

}