com.vmware.identity.session.TomcatAccessLogCleaner.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.identity.session.TomcatAccessLogCleaner.java

Source

/*
 *  Copyright (c) 2012-2015 VMware, Inc.  All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
 *  use this file except in compliance with the License.  You may obtain a copy
 *  of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, without
 *  warranties or conditions of any kind, EITHER EXPRESS OR IMPLIED.  See the
 *  License for the specific language governing permissions and limitations
 *  under the License.
 */

package com.vmware.identity.session;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern;

import org.apache.commons.lang.SystemUtils;

import com.vmware.identity.diagnostics.DiagnosticsLoggerFactory;
import com.vmware.identity.diagnostics.IDiagnosticsLogger;

public class TomcatAccessLogCleaner {

    private static final IDiagnosticsLogger logger = DiagnosticsLoggerFactory
            .getLogger(TomcatAccessLogCleaner.class);
    private static final long TIMER_TASK_DELAY_IN_MILLIS = 3600000; // TODO : tune this param
    private static final String ACCESS_LOG_PATTERN = "localhost_access_log\\.yyyy-MM-dd\\.txt";
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    private static final long MAX_PERMISSIBLE_SIZE_IN_BYTES = 524288000; // 500 MB
    private static final boolean IS_DAEMON = true;

    public TomcatAccessLogCleaner() {

        // Verify the appropriate operating system and assign logDirectory
        File cleanupDirectory = getLogDirectory();

        // Run the Timer which triggers log cleanup tasks at specific interval schedule.
        startLogCleaningProcess(cleanupDirectory);
    }

    /**
     * Perform clean up of the tomcat access log files
     */
    public void startLogCleaningProcess(File accessLogDirectory) {
        logger.info("Cleaning up tomcat access log files under : {}", accessLogDirectory.getAbsolutePath());
        Timer timer = new Timer(IS_DAEMON);
        AccessLogCleanerTask tomcatAccessLogCleaner = new AccessLogCleanerTask(accessLogDirectory);
        logger.info("Starting to schedule the log clean up tasks..");
        timer.scheduleAtFixedRate(tomcatAccessLogCleaner, 0, TIMER_TASK_DELAY_IN_MILLIS);
    }

    /**
     * Get the tomcat access log directory based on operating system.
     */
    private File getLogDirectory() {
        File logDirectory = null;
        if (SystemUtils.IS_OS_LINUX) {
            logDirectory = new File(File.separator + "var" + File.separator + "log" + File.separator + "vmware"
                    + File.separator + "sso");
        } else if (SystemUtils.IS_OS_WINDOWS) {
            String WIN_VMWARE_CIS_VMIDENTITY_PATH = "C:" + File.separator + "ProgramData" + File.separator
                    + "VMware" + File.separator + "vCenterServer" + File.separator + "runtime" + File.separator
                    + "VMWareSTSService" + File.separator + "logs";
            logDirectory = new File(WIN_VMWARE_CIS_VMIDENTITY_PATH);
        } else {
            logger.error("Failed to start tomcat access log cleaner for operatingSystem : {}",
                    System.getProperty("os.name"));
        }
        return logDirectory;
    }

    /**
     * <p>
     * Utility that extends {@link java.util.TimerTask} which cleans up the tomcat access log files on
     * disk which exceeds max threshold size {@value TomcatAccessLogCleaner.MAX_PERMISSIBLE_SIZE_IN_BYTES}. 
     * The file deletion order is based on FIFO structure. (i.e the most out dated file is chosen as primary candidate.)
     * </p>
     * 
     * @author bboggaramrama
     */
    class AccessLogCleanerTask extends TimerTask {

        private Pattern accessLogFilePattern;
        private File accessLogDir;

        public AccessLogCleanerTask(File accessLogDir) {
            this(accessLogDir, ACCESS_LOG_PATTERN);
        }

        public AccessLogCleanerTask(File accessLogDir, String accessLogPattern) {
            this.accessLogDir = accessLogDir;
            this.accessLogFilePattern = Pattern.compile(accessLogPattern.replace(DATE_FORMAT, "(.+?)"));
        }

        @Override
        public void run() {

            // Get all the files matching the given acccess log pattern
            File[] accessLogFiles = retrieveLogFilesMatchingPattern(accessLogDir, accessLogFilePattern);

            if (accessLogFiles != null && accessLogFiles.length > 0) {
                logger.info("Total number of tomcat access log files retrieved : {}", accessLogFiles.length);
                // Compute total size of these files
                long currentTotalSize = 0;
                for (File file : accessLogFiles) {
                    logger.info("Retrieved log file : {}", file.getAbsolutePath());
                    currentTotalSize += file.length();
                }

                // Compare currentsize of these file with total permissible size
                if (currentTotalSize > MAX_PERMISSIBLE_SIZE_IN_BYTES) {
                    logger.info("Trying to delete the files ");
                    // The deletion principle used here is FIFO. (i.e the oldest file is a candidate for deletion )
                    Arrays.sort(accessLogFiles, new Comparator<File>() {
                        public int compare(File file1, File file2) {
                            return Long.valueOf(file1.lastModified()).compareTo(file2.lastModified());
                        }
                    });

                    /**
                     * Delete the files until the totalSize on disk is less than {@value #MAX_PERMISSIBLE_SIZE_IN_BYTES}
                     */
                    for (File file : accessLogFiles) {
                        try {
                            long fileSize = file.length();
                            file.delete();
                            currentTotalSize -= fileSize;
                            if (currentTotalSize < MAX_PERMISSIBLE_SIZE_IN_BYTES)
                                break;
                        } catch (Exception ex) {
                            logger.error("Unable to delete file :{}", file.getAbsolutePath());
                        }
                    }
                } else {
                    // The size of files haven't reached its max permissible size. Wait till it consumes..
                    logger.info("Access logs have not yet reached its threshold ({} mb) to clean. Nothing to clean",
                            MAX_PERMISSIBLE_SIZE_IN_BYTES / (1024 * 1024));
                }
            } else {
                String warnMessage = String.format(
                        "Failed to find tomcat access log file under : '%s'. Nothing to clean",
                        accessLogDir.getAbsolutePath());
                logger.warn(warnMessage);
            }
        }

        /**
         * Retrieve all the files matching the given file pattern
         *
         * @param directory Absolute path of directory
         * @param filePattern Pattern to search for files in given directory
         * @return All files matching the given pattern in a directory
         */
        private File[] retrieveLogFilesMatchingPattern(File directory, final Pattern filePattern) {
            File files[] = null;
            try {
                files = directory.listFiles(new FilenameFilter() {
                    public boolean accept(File dir, String file) {
                        return filePattern.matcher(file).matches();
                    }
                });
            } catch (Exception ex) {
                String errorMessage = String.format(
                        "Failed to retrieve files from directory : %s matching pattern : %s",
                        directory.getAbsolutePath(), filePattern.toString());
                throw new RuntimeException(errorMessage, ex);
            }
            return files;
        }
    }

}