blob: cccb2d16481fdd93b779a6f32009ca1d7a19ca5a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.oozie.service;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.apache.oozie.util.XLogFilter;
import org.apache.oozie.util.Instrumentable;
import org.apache.oozie.util.Instrumentation;
import org.apache.oozie.util.XLog;
import org.apache.oozie.util.XConfiguration;
import org.apache.oozie.BuildInfo;
import org.apache.oozie.ErrorCode;
import org.apache.hadoop.conf.Configuration;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Map;
/**
* Built-in service that initializes and manages Logging via Log4j.
* <p>
* Oozie Lo4gj default configuration file is <code>oozie-log4j.properties</code>.
* <p>
* The file name can be changed by setting the Java System property <code>oozie.log4j.file</code>.
* <p>
* The Log4j configuration files must be a properties file.
* <p>
* The Log4j configuration file is first looked in the Oozie configuration directory see {@link ConfigurationService}.
* If the file is not found there, it is looked in the classpath.
* <p>
* If the Log4j configuration file is loaded from Oozie configuration directory, automatic reloading is enabled.
* <p>
* If the Log4j configuration file is loaded from the classpath, automatic reloading is disabled.
* <p>
* the automatic reloading interval is defined by the Java System property <code>oozie.log4j.reload</code>. The default
* value is 10 seconds.
* <p>
* Unlike most of the other Services, XLogService isn't easily overridable because Services depends on XLogService being available
*/
public class XLogService implements Service, Instrumentable {
private static final String INSTRUMENTATION_GROUP = "logging";
/**
* System property that indicates the logs directory.
*/
public static final String OOZIE_LOG_DIR = "oozie.log.dir";
/**
* System property that indicates the log4j configuration file to load.
*/
public static final String LOG4J_FILE = "oozie.log4j.file";
/**
* System property that indicates the reload interval of the configuration file.
*/
public static final String LOG4J_RELOAD = "oozie.log4j.reload";
/**
* Default value for the log4j configuration file if {@link #LOG4J_FILE} is not set.
*/
public static final String DEFAULT_LOG4J_PROPERTIES = "oozie-log4j.properties";
/**
* Default value for the reload interval if {@link #LOG4J_RELOAD} is not set.
*/
public static final String DEFAULT_RELOAD_INTERVAL = "10";
private XLog log;
private long interval;
private boolean fromClasspath;
private String log4jFileName;
private boolean logOverWS = true;
private boolean errorLogEnabled = true;
private boolean auditLogEnabled = true;
private static final String STARTUP_MESSAGE = "{E}"
+ " ******************************************************************************* {E}"
+ " STARTUP MSG: Oozie BUILD_VERSION [{0}] compiled by [{1}] on [{2}]{E}"
+ " STARTUP MSG: revision [{3}]@[{4}]{E}"
+ "*******************************************************************************";
private String oozieLogPath;
private String oozieLogName;
private String oozieErrorLogPath;
private String oozieErrorLogName;
private String oozieAuditLogPath;
private String oozieAuditLogName;
private int oozieLogRotation = -1;
private int oozieErrorLogRotation = -1;
private int oozieAuditLogRotation = -1;
public XLogService() {
}
public String getOozieLogPath() {
return oozieLogPath;
}
public String getOozieErrorLogPath() {
return oozieErrorLogPath;
}
public String getOozieLogName() {
return oozieLogName;
}
public String getOozieErrorLogName() {
return oozieErrorLogName;
}
/**
* Initialize the log service.
*
* @param services services instance.
* @throws ServiceException thrown if the log service could not be initialized.
*/
public void init(Services services) throws ServiceException {
String oozieHome = Services.getOozieHome();
String oozieLogs = System.getProperty(OOZIE_LOG_DIR, oozieHome + "/logs");
System.setProperty(OOZIE_LOG_DIR, oozieLogs);
try {
LogManager.resetConfiguration();
log4jFileName = System.getProperty(LOG4J_FILE, DEFAULT_LOG4J_PROPERTIES);
if (log4jFileName.contains("/")) {
throw new ServiceException(ErrorCode.E0011, log4jFileName);
}
if (!log4jFileName.endsWith(".properties")) {
throw new ServiceException(ErrorCode.E0012, log4jFileName);
}
String configPath = ConfigurationService.getConfigurationDirectory();
File log4jFile = new File(configPath, log4jFileName);
if (log4jFile.exists()) {
fromClasspath = false;
}
else {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL log4jUrl = cl.getResource(log4jFileName);
if (log4jUrl == null) {
throw new ServiceException(ErrorCode.E0013, log4jFileName, configPath);
}
fromClasspath = true;
}
if (fromClasspath) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL log4jUrl = cl.getResource(log4jFileName);
PropertyConfigurator.configure(log4jUrl);
}
else {
interval = Long.parseLong(System.getProperty(LOG4J_RELOAD, DEFAULT_RELOAD_INTERVAL));
PropertyConfigurator.configureAndWatch(log4jFile.toString(), interval * 1000);
}
log = new XLog(LogFactory.getLog(getClass()));
log.info(XLog.OPS, STARTUP_MESSAGE, BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION),
BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_USER_NAME), BuildInfo.getBuildInfo()
.getProperty(BuildInfo.BUILD_TIME), BuildInfo.getBuildInfo().getProperty(
BuildInfo.BUILD_VC_REVISION), BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VC_URL));
String from = (fromClasspath) ? "CLASSPATH" : configPath;
String reload = (fromClasspath) ? "disabled" : Long.toString(interval) + " sec";
log.info("Log4j configuration file [{0}]", log4jFileName);
log.info("Log4j configuration file loaded from [{0}]", from);
log.info("Log4j reload interval [{0}]", reload);
XLog.Info.reset();
XLog.Info.defineParameter(USER);
XLog.Info.defineParameter(GROUP);
XLogFilter.reset();
XLogFilter.defineParameter(USER);
XLogFilter.defineParameter(GROUP);
// Getting configuration for oozie log via WS
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try ( InputStream is = (fromClasspath) ? cl.getResourceAsStream(log4jFileName) : new FileInputStream(log4jFile); ) {
extractInfoForLogWebService(is);
}
}
catch (IOException ex) {
throw new ServiceException(ErrorCode.E0010, ex.getMessage(), ex);
}
}
private void extractInfoForLogWebService(InputStream is) throws IOException {
Properties props = new Properties();
props.load(is);
XConfiguration conf = new XConfiguration();
conf.setRestrictSystemProperties(false);
for (Map.Entry entry : props.entrySet()) {
conf.set((String) entry.getKey(), (String) entry.getValue());
}
XLogUtil logUtil = new XLogUtil(conf, "oozie");
logOverWS = logUtil.isLogOverEnable();
oozieLogRotation = logUtil.getLogRotation() == 0 ? oozieLogRotation : logUtil.getLogRotation();
oozieLogPath = logUtil.getLogPath() == null ? oozieLogPath : logUtil.getLogPath();
oozieLogName = logUtil.getLogFileName() == null ? oozieLogName : logUtil.getLogFileName();
logUtil = new XLogUtil(conf, "oozieError");
errorLogEnabled = logUtil.isLogOverEnable();
oozieErrorLogRotation = logUtil.getLogRotation() == 0 ? oozieErrorLogRotation : logUtil.getLogRotation();
oozieErrorLogPath = logUtil.getLogPath() == null ? oozieErrorLogPath : logUtil.getLogPath();
oozieErrorLogName = logUtil.getLogFileName() == null ? oozieErrorLogName : logUtil.getLogFileName();
logUtil = new XLogUtil(conf, "oozieaudit");
auditLogEnabled = logUtil.isLogOverEnable();
oozieAuditLogRotation = logUtil.getLogRotation() == 0 ? oozieAuditLogRotation : logUtil.getLogRotation();
oozieAuditLogPath = logUtil.getLogPath() == null ? oozieAuditLogPath : logUtil.getLogPath();
oozieAuditLogName = logUtil.getLogFileName() == null ? oozieAuditLogName : logUtil.getLogFileName();
}
/**
* Destroy the log service.
*/
public void destroy() {
LogManager.shutdown();
XLog.Info.reset();
XLogFilter.reset();
}
/**
* Group log info constant.
*/
public static final String USER = "USER";
/**
* Group log info constant.
*/
public static final String GROUP = "GROUP";
/**
* Return the public interface for log service.
*
* @return {@link XLogService}.
*/
public Class<? extends Service> getInterface() {
return XLogService.class;
}
/**
* Instruments the log service.
* <p>
* It sets instrumentation variables indicating the config file, reload interval and if loaded from the classpath.
*
* @param instr instrumentation to use.
*/
public void instrument(Instrumentation instr) {
instr.addVariable(INSTRUMENTATION_GROUP, "config.file", new Instrumentation.Variable<String>() {
public String getValue() {
return log4jFileName;
}
});
instr.addVariable(INSTRUMENTATION_GROUP, "reload.interval", new Instrumentation.Variable<Long>() {
public Long getValue() {
return interval;
}
});
instr.addVariable(INSTRUMENTATION_GROUP, "from.classpath", new Instrumentation.Variable<Boolean>() {
public Boolean getValue() {
return fromClasspath;
}
});
instr.addVariable(INSTRUMENTATION_GROUP, "log.over.web-service", new Instrumentation.Variable<Boolean>() {
public Boolean getValue() {
return logOverWS;
}
});
}
public boolean getLogOverWS() {
return logOverWS;
}
public boolean isErrorLogEnabled(){
return errorLogEnabled;
}
public int getOozieLogRotation() {
return oozieLogRotation;
}
public int getOozieErrorLogRotation() {
return oozieErrorLogRotation;
}
public int getOozieAuditLogRotation() {
return oozieAuditLogRotation;
}
public String getOozieAuditLogPath() {
return oozieAuditLogPath;
}
public String getOozieAuditLogName() {
return oozieAuditLogName;
}
public boolean isAuditLogEnabled() {
return auditLogEnabled;
}
String getLog4jProperties() {
return log4jFileName;
}
boolean getFromClasspath() {
return fromClasspath;
}
}