/*
* 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.ambari.logfeeder.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.ambari.logfeeder.LogFeeder;
import org.apache.ambari.logfeeder.metrics.MetricData;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
/**
* This class contains utility methods used by LogFeeder
*/
public class LogFeederUtil {
private static final Logger LOG = Logger.getLogger(LogFeederUtil.class);
private final static String GSON_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
private static Gson gson = new GsonBuilder().setDateFormat(GSON_DATE_FORMAT).create();
public static Gson getGson() {
return gson;
}
public static String hostName = null;
public static String ipAddress = null;
static{
try {
InetAddress ip = InetAddress.getLocalHost();
ipAddress = ip.getHostAddress();
String getHostName = ip.getHostName();
String getCanonicalHostName = ip.getCanonicalHostName();
if (!getCanonicalHostName.equalsIgnoreCase(ipAddress)) {
LOG.info("Using getCanonicalHostName()=" + getCanonicalHostName);
hostName = getCanonicalHostName;
} else {
LOG.info("Using getHostName()=" + getHostName);
hostName = getHostName;
}
LOG.info("ipAddress=" + ipAddress + ", getHostName=" + getHostName + ", getCanonicalHostName=" + getCanonicalHostName +
", hostName=" + hostName);
} catch (UnknownHostException e) {
LOG.error("Error getting hostname.", e);
}
}
private static Properties props;
public static Properties getProperties() {
return props;
}
/**
* This method will read the properties from System, followed by propFile and finally from the map
*/
public static void loadProperties(String propFile, String[] propNVList) throws Exception {
LOG.info("Loading properties. propFile=" + propFile);
props = new Properties(System.getProperties());
boolean propLoaded = false;
// First get properties file path from environment value
String propertiesFilePath = System.getProperty("properties");
if (StringUtils.isNotEmpty(propertiesFilePath)) {
File propertiesFile = new File(propertiesFilePath);
if (propertiesFile.exists() && propertiesFile.isFile()) {
LOG.info("Properties file path set in environment. Loading properties file=" + propertiesFilePath);
try (FileInputStream fis = new FileInputStream(propertiesFile)) {
props.load(fis);
propLoaded = true;
} catch (Throwable t) {
LOG.error("Error loading properties file. properties file=" + propertiesFile.getAbsolutePath());
}
} else {
LOG.error("Properties file path set in environment, but file not found. properties file=" + propertiesFilePath);
}
}
if (!propLoaded) {
try (BufferedInputStream bis = (BufferedInputStream) LogFeeder.class.getClassLoader().getResourceAsStream(propFile)) {
// Properties not yet loaded, let's try from class loader
if (bis != null) {
LOG.info("Loading properties file " + propFile + " from classpath");
props.load(bis);
propLoaded = true;
} else {
LOG.fatal("Properties file not found in classpath. properties file name= " + propFile);
}
}
}
if (!propLoaded) {
LOG.fatal("Properties file is not loaded.");
throw new Exception("Properties not loaded");
} else {
updatePropertiesFromMap(propNVList);
}
}
private static void updatePropertiesFromMap(String[] nvList) {
if (nvList == null) {
return;
}
LOG.info("Trying to load additional proeprties from argument paramters. nvList.length=" + nvList.length);
for (String nv : nvList) {
LOG.info("Passed nv=" + nv);
if (nv.startsWith("-") && nv.length() > 1) {
nv = nv.substring(1);
LOG.info("Stripped nv=" + nv);
int i = nv.indexOf("=");
if (nv.length() > i) {
LOG.info("Candidate nv=" + nv);
String name = nv.substring(0, i);
String value = nv.substring(i + 1);
LOG.info("Adding property from argument to properties. name=" + name + ", value=" + value);
props.put(name, value);
}
}
}
}
public static String getStringProperty(String key) {
return props == null ? null : props.getProperty(key);
}
public static String getStringProperty(String key, String defaultValue) {
return props == null ? defaultValue : props.getProperty(key, defaultValue);
}
public static boolean getBooleanProperty(String key, boolean defaultValue) {
String value = getStringProperty(key);
return toBoolean(value, defaultValue);
}
private static boolean toBoolean(String value, boolean defaultValue) {
if (StringUtils.isEmpty(value)) {
return defaultValue;
}
return "true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value);
}
public static int getIntProperty(String key, int defaultValue) {
return getIntProperty(key, defaultValue, null, null);
}
public static int getIntProperty(String key, int defaultValue, Integer minValue, Integer maxValue) {
String value = getStringProperty(key);
int retValue = objectToInt(value, defaultValue, ", key=" + key);
if (minValue != null && retValue < minValue) {
LOG.info("Minimum rule was applied for " + key + ": " + retValue + " < " + minValue);
retValue = minValue;
}
if (maxValue != null && retValue > maxValue) {
LOG.info("Maximum rule was applied for " + key + ": " + retValue + " > " + maxValue);
retValue = maxValue;
}
return retValue;
}
public static int objectToInt(Object objValue, int retValue, String errMessage) {
if (objValue == null) {
return retValue;
}
String strValue = objValue.toString();
if (StringUtils.isNotEmpty(strValue)) {
try {
retValue = Integer.parseInt(strValue);
} catch (Throwable t) {
LOG.error("Error parsing integer value. str=" + strValue + ", " + errMessage);
}
}
return retValue;
}
@SuppressWarnings("unchecked")
public static boolean isEnabled(Map<String, Object> conditionConfigs, Map<String, Object> valueConfigs) {
Map<String, Object> conditions = (Map<String, Object>) conditionConfigs.get("conditions");
if (MapUtils.isEmpty(conditions)) {
return toBoolean((String) valueConfigs.get("is_enabled"), true);
}
for (String conditionType : conditions.keySet()) {
if (!conditionType.equalsIgnoreCase("fields")) {
continue;
}
Map<String, Object> fields = (Map<String, Object>) conditions.get("fields");
for (Map.Entry<String, Object> field : fields.entrySet()) {
if (field.getValue() instanceof String) {
if (isFieldConditionMatch(valueConfigs, field.getKey(), (String) field.getValue())) {
return true;
}
} else {
for (String stringValue : (List<String>) field.getValue()) {
if (isFieldConditionMatch(valueConfigs, field.getKey(), stringValue)) {
return true;
}
}
}
}
}
return false;
}
private static boolean isFieldConditionMatch(Map<String, Object> configs, String fieldName, String stringValue) {
boolean allow = false;
String fieldValue = (String) configs.get(fieldName);
if (fieldValue != null && fieldValue.equalsIgnoreCase(stringValue)) {
allow = true;
} else {
@SuppressWarnings("unchecked")
Map<String, Object> addFields = (Map<String, Object>) configs.get("add_fields");
if (addFields != null && addFields.get(fieldName) != null) {
String addFieldValue = (String) addFields.get(fieldName);
if (stringValue.equalsIgnoreCase(addFieldValue)) {
allow = true;
}
}
}
return allow;
}
public static void logStatForMetric(MetricData metric, String prefixStr, String postFix) {
long currStat = metric.value;
long currMS = System.currentTimeMillis();
if (currStat > metric.prevLogValue) {
LOG.info(prefixStr + ": total_count=" + metric.value + ", duration=" + (currMS - metric.prevLogTime) / 1000 +
" secs, count=" + (currStat - metric.prevLogValue) + postFix);
}
metric.prevLogValue = currStat;
metric.prevLogTime = currMS;
}
public static Map<String, Object> cloneObject(Map<String, Object> map) {
if (map == null) {
return null;
}
String jsonStr = gson.toJson(map);
Type type = new TypeToken<Map<String, Object>>() {}.getType();
return gson.fromJson(jsonStr, type);
}
public static Map<String, Object> toJSONObject(String jsonStr) {
if (StringUtils.isBlank(jsonStr)) {
return new HashMap<String, Object>();
}
Type type = new TypeToken<Map<String, Object>>() {}.getType();
return gson.fromJson(jsonStr, type);
}
private static class LogHistory {
private long lastLogTime = 0;
private int counter = 0;
}
private static Map<String, LogHistory> logHistoryList = new Hashtable<String, LogHistory>();
public static boolean logErrorMessageByInterval(String key, String message, Throwable e, Logger callerLogger, Level level) {
LogHistory log = logHistoryList.get(key);
if (log == null) {
log = new LogHistory();
logHistoryList.put(key, log);
}
if ((System.currentTimeMillis() - log.lastLogTime) > 30 * 1000) {
log.lastLogTime = System.currentTimeMillis();
if (log.counter > 0) {
message += ". Messages suppressed before: " + log.counter;
}
log.counter = 0;
callerLogger.log(level, message, e);
return true;
} else {
log.counter++;
return false;
}
}
private static String logfeederTempDir = null;
public synchronized static String getLogfeederTempDir() {
if (logfeederTempDir == null) {
String tempDirValue = getStringProperty("logfeeder.tmp.dir", "/tmp/$username/logfeeder/");
HashMap<String, String> contextParam = new HashMap<String, String>();
String username = System.getProperty("user.name");
contextParam.put("username", username);
logfeederTempDir = PlaceholderUtil.replaceVariables(tempDirValue, contextParam);
}
return logfeederTempDir;
}
}