Line data Source code
1 : // Copyright (C) 2014 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.util; 16 : 17 : import static java.nio.charset.StandardCharsets.UTF_8; 18 : 19 : import com.google.common.base.Strings; 20 : import com.google.common.flogger.FluentLogger; 21 : import com.google.gerrit.common.Die; 22 : import com.google.gerrit.server.config.GerritServerConfig; 23 : import com.google.gerrit.server.config.SitePaths; 24 : import com.google.inject.Inject; 25 : import com.google.inject.Singleton; 26 : import java.io.IOException; 27 : import java.nio.file.Path; 28 : import org.apache.log4j.Appender; 29 : import org.apache.log4j.AsyncAppender; 30 : import org.apache.log4j.DailyRollingFileAppender; 31 : import org.apache.log4j.FileAppender; 32 : import org.apache.log4j.Layout; 33 : import org.apache.log4j.LogManager; 34 : import org.apache.log4j.Logger; 35 : import org.apache.log4j.helpers.OnlyOnceErrorHandler; 36 : import org.apache.log4j.spi.ErrorHandler; 37 : import org.apache.log4j.spi.LoggingEvent; 38 : import org.eclipse.jgit.lib.Config; 39 : 40 : @Singleton 41 : public class SystemLog { 42 138 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 43 : 44 : public static final String LOG4J_CONFIGURATION = "log4j.configuration"; 45 : 46 : private final SitePaths site; 47 : private final int asyncLoggingBufferSize; 48 : private final boolean rotateLogs; 49 : 50 : @Inject 51 27 : public SystemLog(SitePaths site, @GerritServerConfig Config config) { 52 27 : this.site = site; 53 27 : this.asyncLoggingBufferSize = config.getInt("core", "asyncLoggingBufferSize", 64); 54 27 : this.rotateLogs = config.getBoolean("log", "rotate", true); 55 27 : } 56 : 57 : public static boolean shouldConfigure() { 58 138 : return Strings.isNullOrEmpty(System.getProperty(LOG4J_CONFIGURATION)); 59 : } 60 : 61 : public static Appender createAppender(Path logdir, String name, Layout layout, boolean rotate) { 62 9 : final FileAppender dst = rotate ? new DailyRollingFileAppender() : new FileAppender(); 63 9 : dst.setName(name); 64 9 : dst.setLayout(layout); 65 9 : dst.setEncoding(UTF_8.name()); 66 9 : dst.setFile(resolve(logdir).resolve(name).toString()); 67 9 : dst.setImmediateFlush(true); 68 9 : dst.setAppend(true); 69 9 : dst.setErrorHandler(new DieErrorHandler()); 70 9 : dst.activateOptions(); 71 9 : dst.setErrorHandler(new OnlyOnceErrorHandler()); 72 9 : return dst; 73 : } 74 : 75 : public AsyncAppender createAsyncAppender(String name, Layout layout) { 76 15 : return createAsyncAppender(name, layout, rotateLogs); 77 : } 78 : 79 : private AsyncAppender createAsyncAppender(String name, Layout layout, boolean rotate) { 80 15 : return createAsyncAppender(name, layout, rotate, false); 81 : } 82 : 83 : public AsyncAppender createAsyncAppender( 84 : String name, Layout layout, boolean rotate, boolean forPlugin) { 85 16 : AsyncAppender async = new AsyncAppender(); 86 16 : async.setName(name); 87 16 : async.setBlocking(true); 88 16 : async.setBufferSize(asyncLoggingBufferSize); 89 16 : async.setLocationInfo(false); 90 : 91 16 : if (forPlugin || shouldConfigure()) { 92 9 : async.addAppender(createAppender(site.logs_dir, name, layout, rotate)); 93 : } else { 94 7 : Appender appender = LogManager.getLogger(name).getAppender(name); 95 7 : if (appender != null) { 96 0 : async.addAppender(appender); 97 : } else { 98 7 : logger.atWarning().log( 99 : "No appender with the name: %s was found. %s logging is disabled", name, name); 100 : } 101 : } 102 16 : async.activateOptions(); 103 16 : return async; 104 : } 105 : 106 : private static Path resolve(Path p) { 107 : try { 108 9 : return p.toRealPath().normalize(); 109 0 : } catch (IOException e) { 110 0 : return p.toAbsolutePath().normalize(); 111 : } 112 : } 113 : 114 : private static final class DieErrorHandler implements ErrorHandler { 115 : @Override 116 : public void error(String message, Exception e, int errorCode, LoggingEvent event) { 117 0 : error(e != null ? e.getMessage() : message); 118 0 : } 119 : 120 : @Override 121 : public void error(String message, Exception e, int errorCode) { 122 0 : error(e != null ? e.getMessage() : message); 123 0 : } 124 : 125 : @Override 126 : public void error(String message) { 127 0 : throw new Die("Cannot open log file: " + message); 128 : } 129 : 130 : @Override 131 0 : public void activateOptions() {} 132 : 133 : @Override 134 0 : public void setAppender(Appender appender) {} 135 : 136 : @Override 137 0 : public void setBackupAppender(Appender appender) {} 138 : 139 : @Override 140 0 : public void setLogger(Logger logger) {} 141 : } 142 : }