blob: 9de42fc6f3ad92c6f7b00bcd8cadc43f695265b6 [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.solr.handler.dataimport;
import org.apache.solr.common.util.NamedList;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
/**
* <p>
* Implements most of the interactive development functionality
* </p>
* <p/>
* <p>
* Refer to <a
* href="http://wiki.apache.org/solr/DataImportHandler">http://wiki.apache.org/solr/DataImportHandler</a>
* for more details.
* </p>
* <p/>
* <b>This API is experimental and subject to change</b>
*
* @since solr 1.3
*/
class DebugLogger {
private Stack<DebugInfo> debugStack;
@SuppressWarnings({"rawtypes"})
NamedList output;
// private final SolrWriter writer1;
private static final String LINE = "---------------------------------------------";
private MessageFormat fmt = new MessageFormat(
"----------- row #{0}-------------", Locale.ROOT);
boolean enabled = true;
@SuppressWarnings({"rawtypes"})
public DebugLogger() {
// writer = solrWriter;
output = new NamedList();
debugStack = new Stack<DebugInfo>() {
@Override
public DebugInfo pop() {
if (size() == 1)
throw new DataImportHandlerException(
DataImportHandlerException.SEVERE, "Stack is becoming empty");
return super.pop();
}
};
debugStack.push(new DebugInfo(null, DIHLogLevels.NONE, null));
output = debugStack.peek().lst;
}
private DebugInfo peekStack() {
return debugStack.isEmpty() ? null : debugStack.peek();
}
@SuppressWarnings({"unchecked"})
public void log(DIHLogLevels event, String name, Object row) {
if (event == DIHLogLevels.DISABLE_LOGGING) {
enabled = false;
return;
} else if (event == DIHLogLevels.ENABLE_LOGGING) {
enabled = true;
return;
}
if (!enabled && event != DIHLogLevels.START_ENTITY
&& event != DIHLogLevels.END_ENTITY) {
return;
}
if (event == DIHLogLevels.START_DOC) {
debugStack.push(new DebugInfo(null, DIHLogLevels.START_DOC, peekStack()));
} else if (DIHLogLevels.START_ENTITY == event) {
debugStack
.push(new DebugInfo(name, DIHLogLevels.START_ENTITY, peekStack()));
} else if (DIHLogLevels.ENTITY_OUT == event
|| DIHLogLevels.PRE_TRANSFORMER_ROW == event) {
if (debugStack.peek().type == DIHLogLevels.START_ENTITY
|| debugStack.peek().type == DIHLogLevels.START_DOC) {
debugStack.peek().lst.add(null, fmt.format(new Object[]{++debugStack
.peek().rowCount}));
addToNamedList(debugStack.peek().lst, row);
debugStack.peek().lst.add(null, LINE);
}
} else if (event == DIHLogLevels.ROW_END) {
popAllTransformers();
} else if (DIHLogLevels.END_ENTITY == event) {
while (debugStack.pop().type != DIHLogLevels.START_ENTITY)
;
} else if (DIHLogLevels.END_DOC == event) {
while (debugStack.pop().type != DIHLogLevels.START_DOC)
;
} else if (event == DIHLogLevels.TRANSFORMER_EXCEPTION) {
debugStack.push(new DebugInfo(name, event, peekStack()));
debugStack.peek().lst.add("EXCEPTION",
getStacktraceString((Exception) row));
} else if (DIHLogLevels.TRANSFORMED_ROW == event) {
debugStack.push(new DebugInfo(name, event, peekStack()));
debugStack.peek().lst.add(null, LINE);
addToNamedList(debugStack.peek().lst, row);
debugStack.peek().lst.add(null, LINE);
if (row instanceof DataImportHandlerException) {
DataImportHandlerException dataImportHandlerException = (DataImportHandlerException) row;
dataImportHandlerException.debugged = true;
}
} else if (DIHLogLevels.ENTITY_META == event) {
popAllTransformers();
debugStack.peek().lst.add(name, row);
} else if (DIHLogLevels.ENTITY_EXCEPTION == event) {
if (row instanceof DataImportHandlerException) {
DataImportHandlerException dihe = (DataImportHandlerException) row;
if (dihe.debugged)
return;
dihe.debugged = true;
}
popAllTransformers();
debugStack.peek().lst.add("EXCEPTION",
getStacktraceString((Exception) row));
}
}
private void popAllTransformers() {
while (true) {
DIHLogLevels type = debugStack.peek().type;
if (type == DIHLogLevels.START_DOC || type == DIHLogLevels.START_ENTITY)
break;
debugStack.pop();
}
}
@SuppressWarnings({"unchecked"})
private void addToNamedList(@SuppressWarnings({"rawtypes"})NamedList nl, Object row) {
if (row instanceof List) {
@SuppressWarnings({"rawtypes"})
List list = (List) row;
@SuppressWarnings({"rawtypes"})
NamedList l = new NamedList();
nl.add(null, l);
for (Object o : list) {
Map<String, Object> map = (Map<String, Object>) o;
for (Map.Entry<String, Object> entry : map.entrySet())
nl.add(entry.getKey(), entry.getValue());
}
} else if (row instanceof Map) {
Map<String, Object> map = (Map<String, Object>) row;
for (Map.Entry<String, Object> entry : map.entrySet())
nl.add(entry.getKey(), entry.getValue());
}
}
@SuppressWarnings({"rawtypes"})
DataSource wrapDs(final DataSource ds) {
return new DataSource() {
@Override
public void init(Context context, Properties initProps) {
ds.init(context, initProps);
}
@Override
public void close() {
ds.close();
}
@Override
public Object getData(String query) {
log(DIHLogLevels.ENTITY_META, "query", query);
long start = System.nanoTime();
try {
return ds.getData(query);
} catch (DataImportHandlerException de) {
log(DIHLogLevels.ENTITY_EXCEPTION,
null, de);
throw de;
} catch (Exception e) {
log(DIHLogLevels.ENTITY_EXCEPTION,
null, e);
DataImportHandlerException de = new DataImportHandlerException(
DataImportHandlerException.SEVERE, "", e);
de.debugged = true;
throw de;
} finally {
log(DIHLogLevels.ENTITY_META, "time-taken", DocBuilder
.getTimeElapsedSince(start));
}
}
};
}
Transformer wrapTransformer(final Transformer t) {
return new Transformer() {
@Override
public Object transformRow(Map<String, Object> row, Context context) {
log(DIHLogLevels.PRE_TRANSFORMER_ROW, null, row);
String tName = getTransformerName(t);
Object result = null;
try {
result = t.transformRow(row, context);
log(DIHLogLevels.TRANSFORMED_ROW, tName, result);
} catch (DataImportHandlerException de) {
log(DIHLogLevels.TRANSFORMER_EXCEPTION, tName, de);
de.debugged = true;
throw de;
} catch (Exception e) {
log(DIHLogLevels.TRANSFORMER_EXCEPTION, tName, e);
DataImportHandlerException de = new DataImportHandlerException(DataImportHandlerException.SEVERE, "", e);
de.debugged = true;
throw de;
}
return result;
}
};
}
public static String getStacktraceString(Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
static String getTransformerName(Transformer t) {
@SuppressWarnings({"rawtypes"})
Class transClass = t.getClass();
if (t instanceof EntityProcessorWrapper.ReflectionTransformer) {
return ((EntityProcessorWrapper.ReflectionTransformer) t).trans;
}
if (t instanceof ScriptTransformer) {
ScriptTransformer scriptTransformer = (ScriptTransformer) t;
return "script:" + scriptTransformer.getFunctionName();
}
if (transClass.getPackage().equals(DebugLogger.class.getPackage())) {
return transClass.getSimpleName();
} else {
return transClass.getName();
}
}
private static class DebugInfo {
String name;
int tCount, rowCount;
@SuppressWarnings({"rawtypes"})
NamedList lst;
DIHLogLevels type;
DebugInfo parent;
@SuppressWarnings({"unchecked", "rawtypes"})
public DebugInfo(String name, DIHLogLevels type, DebugInfo parent) {
this.name = name;
this.type = type;
this.parent = parent;
lst = new NamedList();
if (parent != null) {
String displayName = null;
if (type == DIHLogLevels.START_ENTITY) {
displayName = "entity:" + name;
} else if (type == DIHLogLevels.TRANSFORMED_ROW
|| type == DIHLogLevels.TRANSFORMER_EXCEPTION) {
displayName = "transformer:" + name;
} else if (type == DIHLogLevels.START_DOC) {
this.name = displayName = "document#" + SolrWriter.getDocCount();
}
parent.lst.add(displayName, lst);
}
}
}
}