com.facebook.buck.log.LogConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.log.LogConfig.java

Source

/*
 * Copyright 2014-present Facebook, Inc.
 *
 * 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.facebook.buck.log;

import com.facebook.buck.io.MorePaths;
import com.facebook.buck.io.PathListing;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;

import org.stringtemplate.v4.ST;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Optional;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger; // NOPMD

/**
 * Constructed by java.util.logging.LogManager via the system property
 * java.util.logging.LogManager.config.
 *
 * Extends LogManager's support for a single logging.properties file
 * to support a three-level config. Each existent property file is
 * concatenated together and used as a single LogManager configuration,
 * with later entries overriding earlier ones.
 *
 * 1) $BUCK_DIRECTORY/config/logging.properties.st
 * 2) $PROJECT_ROOT/.bucklogging.properties
 * 3) $PROJECT_ROOT/.bucklogging.local.properties
 */
@SuppressWarnings("checkstyle:hideutilityclassconstructor")
public class LogConfig {

    private static final byte[] NEWLINE = { '\n' };

    /**
     * Default constructor, called by LogManager.
     */
    public LogConfig() throws IOException {
        setupLogging(LogConfigSetup.builder().from(LogConfigSetup.DEFAULT_SETUP).setLogFilePrefix("launch-")
                .setCount(1).build());
    }

    /**
     * Creates the log output directory and concatenates logging.properties
     * files together to configure or re-configure LogManager.
     */
    public static synchronized void setupLogging(LogConfigSetup logConfigSetup) throws IOException {
        // Bug JDK-6244047: The default FileHandler does not handle the directory not existing,
        // so we have to create it before any log statements actually run.
        Files.createDirectories(logConfigSetup.getLogDir());

        if (logConfigSetup.getRotateLog()) {
            try {
                deleteOldLogFiles(logConfigSetup);
            } catch (IOException e) {
                System.err.format("Error deleting old log files (ignored): %s\n", e.getMessage());
            }
        }

        ImmutableList.Builder<InputStream> inputStreamsBuilder = ImmutableList.builder();
        if (!LogConfigPaths.MAIN_PATH.isPresent()) {
            System.err.format(
                    "Error: Couldn't read system property %s (it should be set by buck_common or buck.cmd)\n",
                    LogConfigPaths.BUCK_CONFIG_STRING_TEMPLATE_FILE_PROPERTY);
        } else {
            if (!addInputStreamForTemplate(LogConfigPaths.MAIN_PATH.get(), logConfigSetup, inputStreamsBuilder)) {
                System.err.format("Error: Couldn't open logging properties file %s\n",
                        LogConfigPaths.MAIN_PATH.get());
            }
        }

        // We ignore the return value for these files; they don't need to exist.
        addInputStreamForPath(LogConfigPaths.PROJECT_PATH, inputStreamsBuilder);
        addInputStreamForPath(LogConfigPaths.LOCAL_PATH, inputStreamsBuilder);

        // Concatenate each of the files together and read them in as a single properties file
        // for log settings.
        try (InputStream is = new SequenceInputStream(
                Iterators.asEnumeration(inputStreamsBuilder.build().iterator()))) {
            LogManager.getLogManager().readConfiguration(is);
        }
    }

    public static void flushLogs() {
        Logger rootLogger = LogManager.getLogManager().getLogger("");
        if (rootLogger == null) {
            return;
        }
        Handler[] handlers = rootLogger.getHandlers();
        if (handlers == null) {
            return;
        }
        for (Handler h : Arrays.asList(handlers)) {
            h.flush();
        }
    }

    private static boolean addInputStreamForTemplate(Path path, LogConfigSetup logConfigSetup,
            ImmutableList.Builder<InputStream> inputStreamsBuilder) throws IOException {
        try {
            String template = new String(Files.readAllBytes(path), Charsets.UTF_8);
            ST st = new ST(template);
            st.add("default_file_pattern",
                    MorePaths.pathWithUnixSeparators(logConfigSetup.getLogFilePath()).toString());
            st.add("default_count", logConfigSetup.getCount());
            st.add("default_max_size_bytes", logConfigSetup.getMaxLogSizeBytes());
            String result = st.render();
            inputStreamsBuilder.add(new ByteArrayInputStream(result.getBytes(Charsets.UTF_8)));
            inputStreamsBuilder.add(new ByteArrayInputStream(NEWLINE));
            return true;
        } catch (FileNotFoundException e) {
            return false;
        }
    }

    private static boolean addInputStreamForPath(Path path,
            ImmutableList.Builder<InputStream> inputStreamsBuilder) {
        try {
            inputStreamsBuilder.add(new FileInputStream(path.toString()));
            // Handle the case where a file doesn't end with a newline.
            inputStreamsBuilder.add(new ByteArrayInputStream(NEWLINE));
            return true;
        } catch (FileNotFoundException e) {
            return false;
        }
    }

    private static void deleteOldLogFiles(LogConfigSetup logConfigSetup) throws IOException {
        for (Path path : PathListing.listMatchingPathsWithFilters(logConfigSetup.getLogDir(),
                logConfigSetup.getLogFilePrefix() + "*.log*", PathListing.GET_PATH_MODIFIED_TIME,
                PathListing.FilterMode.EXCLUDE, Optional.empty(),
                Optional.of(logConfigSetup.getMaxLogSizeBytes()))) {
            Files.deleteIfExists(path);
        }
    }
}