blob: fa3536eb10c139c9805cff7a877b89baeb0696cd [file] [log] [blame]
/*
* 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.PathListing;
import com.facebook.buck.util.BuckConstant;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
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.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger;
/**
* 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
* 2) $PROJECT_ROOT/.bucklogging.properties
* 3) $PROJECT_ROOT/.bucklogging.local.properties
*/
@SuppressWarnings("checkstyle:hideutilityclassconstructor")
public class LogConfig {
private static final byte[] NEWLINE = {'\n'};
private static final long MAX_LOG_SIZE = 100 * 1024 * 1024;
/**
* Default constructor, called by LogManager.
*/
public LogConfig() throws IOException {
setupLogging();
}
/**
* Creates the log output directory and concatenates logging.properties
* files together to configure or re-configure LogManager.
*/
public static synchronized void setupLogging() 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(BuckConstant.LOG_PATH);
try {
deleteOldLogFiles();
} 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_FILE_PROPERTY);
} else {
if (!addInputStreamForPath(LogConfigPaths.MAIN_PATH.get(), 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 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() throws IOException {
for (Path path : PathListing.listMatchingPathsWithFilters(
BuckConstant.LOG_PATH,
"buck-*.log*",
PathListing.GET_PATH_MODIFIED_TIME,
PathListing.FilterMode.EXCLUDE,
Optional.<Integer>absent(),
Optional.of(MAX_LOG_SIZE))) {
Files.deleteIfExists(path);
}
}
}