blob: b73da2fd4219b4e5dc59a2141f04d687c277fc57 [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.cloudstack.syslog;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.net.SyslogAppender;
import org.apache.log4j.spi.LoggingEvent;
import com.cloud.utils.net.NetUtils;
public class AlertsSyslogAppender extends AppenderSkeleton {
String _syslogHosts = null;
String _delimiter = ",";
List<String> _syslogHostsList = null;
List<SyslogAppender> _syslogAppenders = null;
private String _facility;
private String _pairDelimiter = "//";
private String _keyValueDelimiter = "::";
private int alertType = -1;
private long dataCenterId = 0;
private long podId = 0;
private long clusterId = 0;
private String sysMessage = null;
public static final int LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER = 9;
public static final int LENGTH_OF_STRING_MESSAGE = 8;
public static final String MESSAGE_DELIMITER_STRING = " ";
//add the alertType in this array it its level needs to be set to critical
private static final int[] criticalAlerts = {7, 8, 9, 10, 11, 12, 13, 15, 16, 19, 20, 27};
private static final Map<Integer, String> alertsMap;
static {
Map<Integer, String> aMap = new HashMap<Integer, String>(27);
aMap.put(0, "availableMemory");
aMap.put(1, "availableCpu");
aMap.put(2, "availableStorage");
aMap.put(3, "remainingStorageAllocated");
aMap.put(4, "unallocatedVirtualNetworkpublicIp");
aMap.put(5, "unallocatedPrivateIp");
aMap.put(6, "availableSecondaryStorage");
aMap.put(7, "host");
aMap.put(8, "userVmState");
aMap.put(9, "domainRouterVmState ");
aMap.put(10, "consoleProxyVmState");
aMap.put(11, "routingConnection");
aMap.put(12, "storageIssueSystemVms");
aMap.put(13, "usageServerStatus");
aMap.put(14, "managementNode");
aMap.put(15, "domainRouterMigrate");
aMap.put(16, "consoleProxyMigrate");
aMap.put(17, "userVmMigrate");
aMap.put(18, "unallocatedVlan");
aMap.put(19, "ssvmStopped");
aMap.put(20, "usageServerResult");
aMap.put(21, "storageDelete");
aMap.put(22, "updateResourceCount");
aMap.put(23, "usageSanityResult");
aMap.put(24, "unallocatedDirectAttachedPublicIp");
aMap.put(25, "unallocatedLocalStorage");
aMap.put(26, "resourceLimitExceeded");
aMap.put(27, "sync");
alertsMap = Collections.unmodifiableMap(aMap);
}
@Override
protected void append(LoggingEvent event) {
if (!isAsSevereAsThreshold(event.getLevel())) {
return;
}
if (_syslogAppenders != null && !_syslogAppenders.isEmpty()) {
try {
String logMessage = event.getRenderedMessage();
if (logMessage.contains("alertType") && logMessage.contains("message")) {
parseMessage(logMessage);
String syslogMessage = createSyslogMessage();
LoggingEvent syslogEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getLevel(), syslogMessage, null);
for (SyslogAppender syslogAppender : _syslogAppenders) {
syslogAppender.append(syslogEvent);
}
}
} catch (Exception e) {
errorHandler.error(e.getMessage());
}
}
}
@Override
synchronized public void close() {
for (SyslogAppender syslogAppender : _syslogAppenders) {
syslogAppender.close();
}
}
@Override
public boolean requiresLayout() {
return true;
}
void setSyslogAppenders() {
if (_syslogAppenders == null) {
_syslogAppenders = new ArrayList<SyslogAppender>();
}
if (_syslogHosts == null || _syslogHosts.trim().isEmpty()) {
reset();
return;
}
_syslogHostsList = parseSyslogHosts(_syslogHosts);
if (!validateIpAddresses()) {
reset();
errorHandler.error(" Invalid format for the IP Addresses parameter ");
return;
}
for (String syslogHost : _syslogHostsList) {
_syslogAppenders.add(new SyslogAppender(getLayout(), syslogHost, SyslogAppender.getFacility(_facility)));
}
}
private List<String> parseSyslogHosts(String syslogHosts) {
List<String> result = new ArrayList<String>();
final StringTokenizer tokenizer = new StringTokenizer(syslogHosts, _delimiter);
while (tokenizer.hasMoreTokens()) {
result.add(tokenizer.nextToken().trim());
}
return result;
}
private boolean validateIpAddresses() {
for (String ipAddress : _syslogHostsList) {
String[] hostTokens = (ipAddress.trim()).split(":");
String ip = hostTokens[0];
if (hostTokens.length >= 1 && hostTokens.length <= 2) {
if (hostTokens.length == 2 && !NetUtils.isValidPort(hostTokens[1])) {
return false;
}
if (ip.equalsIgnoreCase("localhost")) {
continue;
}
if (!NetUtils.isValidIp4(ip)) {
return false;
}
} else
{
return false;
}
}
return true;
}
void parseMessage(String logMessage) {
final StringTokenizer messageSplitter = new StringTokenizer(logMessage, _pairDelimiter);
while (messageSplitter.hasMoreTokens()) {
final String pairToken = messageSplitter.nextToken();
final StringTokenizer pairSplitter = new StringTokenizer(pairToken, _keyValueDelimiter);
String keyToken;
String valueToken;
if (pairSplitter.hasMoreTokens()) {
keyToken = pairSplitter.nextToken().trim();
} else {
break;
}
if (pairSplitter.hasMoreTokens()) {
valueToken = pairSplitter.nextToken().trim();
} else {
break;
}
if (keyToken.equalsIgnoreCase("alertType") && !valueToken.equalsIgnoreCase("null")) {
alertType = Short.parseShort(valueToken);
} else if (keyToken.equalsIgnoreCase("dataCenterId") && !valueToken.equalsIgnoreCase("null")) {
dataCenterId = Long.parseLong(valueToken);
} else if (keyToken.equalsIgnoreCase("podId") && !valueToken.equalsIgnoreCase("null")) {
podId = Long.parseLong(valueToken);
} else if (keyToken.equalsIgnoreCase("clusterId") && !valueToken.equalsIgnoreCase("null")) {
clusterId = Long.parseLong(valueToken);
} else if (keyToken.equalsIgnoreCase("message") && !valueToken.equalsIgnoreCase("null")) {
sysMessage = getSyslogMessage(logMessage);
}
}
}
String createSyslogMessage() {
StringBuilder message = new StringBuilder();
message.append(severityOfAlert(alertType)).append(MESSAGE_DELIMITER_STRING);
InetAddress ip;
try {
ip = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
ip = null;
}
if (ip != null) {
message.append(ip.getHostName()).append(MESSAGE_DELIMITER_STRING);
} else {
message.append("unknown" + MESSAGE_DELIMITER_STRING);
}
if (alertType >= 0) {
message.append("alertType").append(_keyValueDelimiter).append(" ").append(alertsMap.containsKey(alertType) ? alertsMap.get(alertType) : "unknown")
.append(MESSAGE_DELIMITER_STRING);
if (dataCenterId != 0) {
message.append("dataCenterId").append(_keyValueDelimiter).append(" ").append(dataCenterId).append(MESSAGE_DELIMITER_STRING);
}
if (podId != 0) {
message.append("podId").append(_keyValueDelimiter).append(" ").append(podId).append(MESSAGE_DELIMITER_STRING);
}
if (clusterId != 0) {
message.append("clusterId").append(_keyValueDelimiter).append(" ").append(clusterId).append(MESSAGE_DELIMITER_STRING);
}
if (sysMessage != null) {
message.append("message").append(_keyValueDelimiter).append(" ").append(sysMessage);
} else {
errorHandler.error("What is the use of alert without message ");
}
} else {
errorHandler.error("Invalid alert Type ");
}
return message.toString();
}
private String getSyslogMessage(String message) {
int lastIndexOfKeyValueDelimiter = message.lastIndexOf(_keyValueDelimiter);
int lastIndexOfMessageInString = message.lastIndexOf("message");
if (lastIndexOfKeyValueDelimiter - lastIndexOfMessageInString <= LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER) {
return message.substring(lastIndexOfKeyValueDelimiter + _keyValueDelimiter.length()).trim();
} else if (lastIndexOfMessageInString < lastIndexOfKeyValueDelimiter) {
return message.substring(lastIndexOfMessageInString + _keyValueDelimiter.length() + LENGTH_OF_STRING_MESSAGE).trim();
}
return message.substring(message.lastIndexOf("message" + _keyValueDelimiter) + LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER).trim();
}
private void reset() {
_syslogAppenders.clear();
}
public void setFacility(String facility) {
if (facility == null) {
return;
}
_facility = facility;
if (_syslogAppenders != null && !_syslogAppenders.isEmpty()) {
for (SyslogAppender syslogAppender : _syslogAppenders) {
syslogAppender.setFacility(facility);
}
}
}
private String severityOfAlert(int alertType) {
if (isCritical(alertType)) {
return "CRITICAL";
} else {
return "WARN";
}
}
private boolean isCritical(int alertType) {
for (int type : criticalAlerts) {
if (type == alertType) {
return true;
}
}
return false;
}
public String getFacility() {
return _facility;
}
public String getSyslogHosts() {
return _syslogHosts;
}
public void setSyslogHosts(String syslogHosts) {
_syslogHosts = syslogHosts;
setSyslogAppenders();
}
public String getDelimiter() {
return _delimiter;
}
public void setDelimiter(String delimiter) {
_delimiter = delimiter;
}
public String getPairDelimiter() {
return _pairDelimiter;
}
public void setPairDelimiter(String pairDelimiter) {
_pairDelimiter = pairDelimiter;
}
public String getKeyValueDelimiter() {
return _keyValueDelimiter;
}
public void setKeyValueDelimiter(String keyValueDelimiter) {
_keyValueDelimiter = keyValueDelimiter;
}
}