/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2010, 2014, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
****************************************************************************/
package org.zenoss.zep.index.impl.solr;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zenoss.protobufs.zep.Zep.Event;
import org.zenoss.protobufs.zep.Zep.EventActor;
import org.zenoss.protobufs.zep.Zep.EventDetail;
import org.zenoss.protobufs.zep.Zep.EventDetailItem;
import org.zenoss.protobufs.zep.Zep.EventSummary;
import org.zenoss.protobufs.zep.Zep.EventTag;
import org.zenoss.zep.ZepException;
import org.zenoss.zep.index.impl.BaseEventIndexMapper;
import org.zenoss.zep.index.impl.IndexConstants;
import org.zenoss.zep.utils.IpUtils;
public class SolrEventIndexMapper extends BaseEventIndexMapper {
public static final String DETAIL_INDEX_PREFIX = "details_";
public static final String BELL_CHARACTER = Character.toString((char)7);
private static final Logger logger = LoggerFactory.getLogger(SolrEventIndexMapper.class);
public static SolrInputDocument fromEventSummary(EventSummary summary, Map<String, EventDetailItem> detailsConfig) throws ZepException {
final Event event = summary.getOccurrence(0);
final EventActor actor = event.getActor();
SolrInputDocument doc = new SolrInputDocument();
if (!isArchive(event)) // See ZEN-2159
doc.addField(IndexConstants.FIELD_PROTOBUF, compressProtobuf(summary));
doc.addField(IndexConstants.FIELD_UUID, summary.getUuid());
doc.addField(IndexConstants.FIELD_CURRENT_USER_NAME, summary.getCurrentUserName());
doc.addField(IndexConstants.FIELD_STATUS, summary.getStatus().getNumber());
doc.addField(IndexConstants.FIELD_COUNT, summary.getCount());
doc.addField(IndexConstants.FIELD_LAST_SEEN_TIME, summary.getLastSeenTime());
doc.addField(IndexConstants.FIELD_FIRST_SEEN_TIME, summary.getFirstSeenTime());
doc.addField(IndexConstants.FIELD_STATUS_CHANGE_TIME, summary.getStatusChangeTime());
doc.addField(IndexConstants.FIELD_UPDATE_TIME, summary.getUpdateTime());
doc.addField(IndexConstants.FIELD_FINGERPRINT, event.getFingerprint());
doc.addField(IndexConstants.FIELD_SUMMARY, event.getSummary());
doc.addField(IndexConstants.FIELD_SEVERITY, event.getSeverity().getNumber());
doc.addField(IndexConstants.FIELD_EVENT_CLASS, event.getEventClass());
doc.addField(IndexConstants.FIELD_AGENT, event.getAgent());
doc.addField(IndexConstants.FIELD_MONITOR, event.getMonitor());
doc.addField(IndexConstants.FIELD_EVENT_KEY, event.getEventKey());
doc.addField(IndexConstants.FIELD_EVENT_CLASS_KEY, event.getEventClassKey());
doc.addField(IndexConstants.FIELD_EVENT_GROUP, event.getEventGroup());
doc.addField(IndexConstants.FIELD_MESSAGE, event.getMessage());
for (EventTag tag : event.getTagsList())
for (String tagUuid : tag.getUuidList())
doc.addField(IndexConstants.FIELD_TAGS, tagUuid);
final String uuid = actor.getElementUuid();
if (uuid != null && !uuid.isEmpty())
doc.addField(IndexConstants.FIELD_TAGS, uuid);
doc.addField(IndexConstants.FIELD_ELEMENT_IDENTIFIER, actor.getElementIdentifier());
doc.addField(IndexConstants.FIELD_ELEMENT_TITLE, actor.getElementTitle());
String subUuid = actor.getElementSubUuid();
if (subUuid != null && !subUuid.isEmpty())
doc.addField(IndexConstants.FIELD_TAGS, subUuid);
doc.addField(IndexConstants.FIELD_ELEMENT_SUB_IDENTIFIER, actor.getElementSubIdentifier());
doc.addField(IndexConstants.FIELD_ELEMENT_SUB_TITLE, actor.getElementSubTitle());
Set<String> remainingDetails = Sets.newHashSet(detailsConfig.keySet());
for (EventDetail detail : event.getDetailsList()) {
final String name = detail.getName();
final EventDetailItem item = detailsConfig.get(name);
if (item == null) continue;
remainingDetails.remove(name);
EventDetailItem.EventDetailType type = item.getType();
final String detailKey = DETAIL_INDEX_PREFIX + item.getKey();
for (String value : detail.getValueList()) {
try {
switch (type) {
case STRING:
doc.addField(detailKey + "_s", value);
doc.addField(detailKey + "_s_sort", value);
break;
case INTEGER:
doc.addField(detailKey + "_i", Integer.parseInt(value));
break;
case FLOAT:
doc.addField(detailKey + "_f", Float.parseFloat(value));
break;
case LONG:
doc.addField(detailKey + "_l", Long.parseLong(value));
break;
case DOUBLE:
doc.addField(detailKey + "_d", Double.parseDouble(value));
break;
case PATH:
doc.addField(detailKey + "_path", value);
//NOTE: PATH details are not sortable, because some may be multi-valued.
break;
case IP_ADDRESS:
if (value.isEmpty()) continue;
final InetAddress addr = IpUtils.parseAddress(value);
final String ipType = (addr instanceof Inet6Address) ?
IndexConstants.IP_ADDRESS_TYPE_6 :
IndexConstants.IP_ADDRESS_TYPE_4;
doc.addField(detailKey + "_ip", addr.getHostAddress());
doc.addField(detailKey + "_ip_type", ipType);
doc.addField(detailKey + "_ip_sort", IpUtils.canonicalIpAddress(addr));
break;
default:
throw new IllegalStateException("Unexpected type: " + item.getType());
}
} catch (IllegalArgumentException e) {
logger.warn(String.format("Invalid data reported for detail %s(%s): %s", name, type, value));
} catch (IllegalStateException e) {
logger.warn(String.format("Invalid data reported for detail %s(%s): %s", name, type, value));
} catch (NullPointerException e) {
logger.warn(String.format("Invalid data reported for detail %s(%s): %s", name, type, value));
}
}
}
for (String name : remainingDetails) {
final String detailKey = DETAIL_INDEX_PREFIX + name;
final EventDetailItem item = detailsConfig.get(name);
switch (item.getType()) {
case STRING:
doc.addField(detailKey + "_s", BELL_CHARACTER);
break;
case INTEGER:
doc.addField(detailKey + "_i", Integer.MIN_VALUE);
break;
case FLOAT:
doc.addField(detailKey + "_f", Integer.MIN_VALUE);
break;
case LONG:
doc.addField(detailKey + "_l", Integer.MIN_VALUE);
break;
case DOUBLE:
doc.addField(detailKey + "_d", Integer.MIN_VALUE);
break;
case IP_ADDRESS:
doc.addField(detailKey + "_ip", BELL_CHARACTER);
break;
case PATH:
doc.addField(detailKey + "_path", BELL_CHARACTER);
break;
default:
throw new IllegalStateException("Unexpected type: " + item.getType());
}
}
return doc;
}
public static boolean isArchive(final Event event) {
List<String> values = getDetail(event, "is_archive");
if (values == null) return false;
for (String value : values)
if ("true".equals(value)) return true;
return false;
}
public static List<String> getDetail(final Event event, final String detailName) {
final int count = event.getDetailsCount();
List<String> values = null;
for (int i = 0; i < count; i++) {
final EventDetail detail = event.getDetails(i);
if (detailName.equals(detail.getName())) {
if (values == null)
values = Lists.newArrayList();
values.addAll(detail.getValueList());
}
}
return values;
}
public static EventSummary toEventSummary(SolrDocument item) throws ZepException {
final byte[] protobuf = (byte[]) item.getFieldValue(IndexConstants.FIELD_PROTOBUF);
if (protobuf != null)
return uncompressProtobuf(protobuf);
final String uuid = (String) item.getFieldValue(IndexConstants.FIELD_UUID);
final Long lastSeen = (Long) item.getFieldValue(IndexConstants.FIELD_LAST_SEEN_TIME);
final EventSummary.Builder builder = EventSummary.newBuilder();
if (uuid != null)
builder.setUuid(uuid);
if (lastSeen != null)
builder.setLastSeenTime(lastSeen);
return builder.build();
}
}