/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.dataflow.ops;
import com.espertech.esper.client.EPRuntime;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.util.*;
import com.espertech.esper.dataflow.annotations.DataFlowOpParameter;
import com.espertech.esper.dataflow.annotations.DataFlowOperator;
import com.espertech.esper.dataflow.interfaces.*;
import com.espertech.esper.epl.expression.core.ExprValidationException;
import com.espertech.esper.event.EventBeanSPI;
import com.espertech.esper.event.EventBeanUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@DataFlowOperator
public class LogSink implements DataFlowOpLifecycle {
private static final Logger LOGME = LoggerFactory.getLogger(LogSink.class);
@DataFlowOpParameter
private String title;
@DataFlowOpParameter
private String layout;
@DataFlowOpParameter
private String format;
@DataFlowOpParameter
private boolean log = true;
@DataFlowOpParameter
private boolean linefeed = true;
private String dataflowName;
private String dataFlowInstanceId;
private ConsoleOpRenderer renderer;
private EventBeanSPI[] shellPerStream;
public DataFlowOpInitializeResult initialize(DataFlowOpInitializateContext context) throws Exception {
if (!context.getOutputPorts().isEmpty()) {
throw new IllegalArgumentException("LogSink operator does not provide an output stream");
}
dataflowName = context.getDataflowName();
dataFlowInstanceId = context.getDataflowInstanceId();
shellPerStream = new EventBeanSPI[context.getInputPorts().size()];
for (Map.Entry<Integer, DataFlowOpInputPort> entry : context.getInputPorts().entrySet()) {
EventType eventType = entry.getValue().getTypeDesc().getEventType();
if (eventType != null) {
shellPerStream[entry.getKey()] = context.getStatementContext().getEventAdapterService().getShellForType(eventType);
}
}
if (format == null) {
renderer = new ConsoleOpRendererSummary();
} else {
try {
LogSinkOutputFormat formatEnum = LogSinkOutputFormat.valueOf(format.trim().toLowerCase(Locale.ENGLISH));
if (formatEnum == LogSinkOutputFormat.summary) {
renderer = new ConsoleOpRendererSummary();
} else {
renderer = new ConsoleOpRendererXmlJSon(formatEnum, context.getEngine().getEPRuntime());
}
} catch (RuntimeException ex) {
throw new ExprValidationException("Format '" + format + "' is not supported, expecting any of " + Arrays.toString(LogSinkOutputFormat.values()));
}
}
return null;
}
public void open(DataFlowOpOpenContext openContext) {
}
public void close(DataFlowOpCloseContext openContext) {
}
public void onInput(int port, Object theEvent) {
String line;
if (layout == null) {
StringWriter writer = new StringWriter();
writer.write("[");
writer.write(dataflowName);
writer.write("] ");
if (title != null) {
writer.write("[");
writer.write(title);
writer.write("] ");
}
if (dataFlowInstanceId != null) {
writer.write("[");
writer.write(dataFlowInstanceId);
writer.write("] ");
}
writer.write("[port ");
writer.write(Integer.toString(port));
writer.write("] ");
getEventOut(port, theEvent, writer);
line = writer.toString();
} else {
String result = layout.replace("%df", dataflowName).replace("%p", Integer.toString(port));
if (dataFlowInstanceId != null) {
result = result.replace("%i", dataFlowInstanceId);
}
if (title != null) {
result = result.replace("%t", title);
}
StringWriter writer = new StringWriter();
getEventOut(port, theEvent, writer);
result = result.replace("%e", writer.toString());
line = result;
}
if (!linefeed) {
line = line.replaceAll("\n", "").replaceAll("\r", "");
}
// output
if (log) {
LOGME.info(line);
} else {
System.out.println(line);
}
}
private void getEventOut(int port, Object theEvent, StringWriter writer) {
if (theEvent instanceof EventBean) {
renderer.render((EventBean) theEvent, writer);
return;
}
if (shellPerStream[port] != null) {
synchronized (this) {
shellPerStream[port].setUnderlying(theEvent);
renderer.render(shellPerStream[port], writer);
}
return;
}
writer.write("Unrecognized underlying: ");
writer.write(theEvent.toString());
}
public static enum LogSinkOutputFormat {
json,
xml,
summary
}
public interface ConsoleOpRenderer {
public void render(EventBean eventBean, StringWriter writer);
}
public static class ConsoleOpRendererSummary implements ConsoleOpRenderer {
public void render(EventBean theEvent, StringWriter writer) {
EventBeanUtility.summarize(theEvent, writer);
}
}
public static class ConsoleOpRendererXmlJSon implements ConsoleOpRenderer {
private final LogSinkOutputFormat format;
private final EPRuntime runtime;
private final Map<EventType, JSONEventRenderer> jsonRendererCache = new HashMap<EventType, JSONEventRenderer>();
private final Map<EventType, XMLEventRenderer> xmlRendererCache = new HashMap<EventType, XMLEventRenderer>();
public ConsoleOpRendererXmlJSon(LogSinkOutputFormat format, EPRuntime runtime) {
this.format = format;
this.runtime = runtime;
}
public void render(EventBean theEvent, StringWriter writer) {
String result;
if (format == LogSinkOutputFormat.json) {
JSONEventRenderer renderer = jsonRendererCache.get(theEvent.getEventType());
if (renderer == null) {
renderer = getJsonRenderer(theEvent.getEventType());
jsonRendererCache.put(theEvent.getEventType(), renderer);
}
result = renderer.render(theEvent.getEventType().getName(), theEvent);
} else {
XMLEventRenderer renderer = xmlRendererCache.get(theEvent.getEventType());
if (renderer == null) {
renderer = getXmlRenderer(theEvent.getEventType());
xmlRendererCache.put(theEvent.getEventType(), renderer);
}
result = renderer.render(theEvent.getEventType().getName(), theEvent);
}
writer.append(result);
}
protected JSONEventRenderer getJsonRenderer(EventType eventType) {
return runtime.getEventRenderer().getJSONRenderer(eventType, RenderingOptions.getJsonOptions());
}
protected XMLEventRenderer getXmlRenderer(EventType eventType) {
return runtime.getEventRenderer().getXMLRenderer(eventType, RenderingOptions.getXmlOptions());
}
}
public static class RenderingOptions {
private static XMLRenderingOptions xmlOptions;
private static JSONRenderingOptions jsonOptions;
static {
xmlOptions = new XMLRenderingOptions();
xmlOptions.setPreventLooping(true);
xmlOptions.setRenderer(ConsoleOpEventPropertyRenderer.INSTANCE);
jsonOptions = new JSONRenderingOptions();
jsonOptions.setPreventLooping(true);
jsonOptions.setRenderer(ConsoleOpEventPropertyRenderer.INSTANCE);
}
public static XMLRenderingOptions getXmlOptions() {
return xmlOptions;
}
public static void setXmlOptions(XMLRenderingOptions xmlOptions) {
RenderingOptions.xmlOptions = xmlOptions;
}
public static JSONRenderingOptions getJsonOptions() {
return jsonOptions;
}
public static void setJsonOptions(JSONRenderingOptions jsonOptions) {
RenderingOptions.jsonOptions = jsonOptions;
}
}
public static class ConsoleOpEventPropertyRenderer implements EventPropertyRenderer {
public final static ConsoleOpEventPropertyRenderer INSTANCE = new ConsoleOpEventPropertyRenderer();
public void render(EventPropertyRendererContext context) {
if (context.getPropertyValue() instanceof Object[]) {
context.getStringBuilder().append(Arrays.toString((Object[]) context.getPropertyValue()));
} else {
context.getDefaultRenderer().render(context.getPropertyValue(), context.getStringBuilder());
}
}
}
}