/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2009 Wolfgang M. Meier
* wolfgang@exist-db.org
* http://exist.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.xquery.functions.util;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.dom.QName;
import org.exist.source.StringSource;
import org.exist.storage.serializers.Serializer;
import org.exist.xquery.*;
import org.exist.xquery.value.*;
import org.xml.sax.SAXException;
/**
* @author Wolfgang Meier (wolfgang@exist-db.org)
* @author Andrzej Taramina (andrzej@chaeron.com)
*/
public class LogFunction extends BasicFunction {
protected static final FunctionParameterSequenceType PRIORITY_PARAMETER
= new FunctionParameterSequenceType("priority", Type.STRING, Cardinality.EXACTLY_ONE, "The logging priority: 'error', 'warn', 'debug', 'info', 'trace'");
protected static final FunctionParameterSequenceType LOGGER_NAME_PARAMETER
= new FunctionParameterSequenceType("logger-name", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the logger, eg: my.app.log");
protected static final FunctionParameterSequenceType MESSAGE_PARAMETER
= new FunctionParameterSequenceType("message", Type.ITEM, Cardinality.ZERO_OR_MORE, "The message to log");
protected static final Logger logger = LogManager.getLogger(LogFunction.class);
public static final String FUNCTION_LOG = "log";
public static final String FUNCTION_LOGAPP = "log-app";
public static final String FUNCTION_LOG_SYSTEM_OUT = "log-system-out";
public static final String FUNCTION_LOG_SYSTEM_ERR = "log-system-err";
public final static FunctionSignature signatures[] = {
new FunctionSignature(
new QName(FUNCTION_LOG, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
"Logs the message to the current logger.",
new SequenceType[]{PRIORITY_PARAMETER, MESSAGE_PARAMETER},
new SequenceType(Type.ITEM, Cardinality.EMPTY)
),
new FunctionSignature(
new QName(FUNCTION_LOG_SYSTEM_OUT, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
"Logs the message to System.out.",
new SequenceType[]{MESSAGE_PARAMETER},
new SequenceType(Type.ITEM, Cardinality.EMPTY)
),
new FunctionSignature(
new QName(FUNCTION_LOG_SYSTEM_ERR, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
"Logs the message to System.err.",
new SequenceType[]{MESSAGE_PARAMETER},
new SequenceType(Type.ITEM, Cardinality.EMPTY)
),
new FunctionSignature(
new QName(FUNCTION_LOGAPP, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
"Logs the message to the named logger",
new SequenceType[]{PRIORITY_PARAMETER, LOGGER_NAME_PARAMETER, MESSAGE_PARAMETER},
new SequenceType(Type.ITEM, Cardinality.EMPTY)
)
};
public LogFunction(XQueryContext context, FunctionSignature signature) {
super(context, signature);
}
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
SequenceIterator i;
final String calledAs = getName().getLocalPart();
// Find query parameter with actual data
switch (calledAs) {
case FUNCTION_LOG:
i = args[1].unorderedIterator();
if (args[1].isEmpty()) {
return (Sequence.EMPTY_SEQUENCE);
}
break;
case FUNCTION_LOGAPP:
i = args[2].unorderedIterator();
if (args[2].isEmpty()) {
return (Sequence.EMPTY_SEQUENCE);
}
break;
default:
i = args[0].unorderedIterator();
if (args[0].isEmpty()) {
return (Sequence.EMPTY_SEQUENCE);
}
break;
}
// Add line of the log statement
final StringBuilder buf = new StringBuilder();
buf.append("(");
buf.append("Line: ");
buf.append(this.getLine());
// Add source information to the log statement when provided
if (getSource() != null && getSource().getKey() != null) {
buf.append(" ");
// Do not write content of query from String into log.
if (getSource() instanceof StringSource) {
buf.append(getSource().type());
} else {
buf.append(getSource().getKey());
}
}
buf.append(") ");
// Iterate over all input
while (i.hasNext()) {
final Item next = i.nextItem();
if (Type.subTypeOf(next.getType(), Type.NODE)) {
final Serializer serializer = context.getBroker().getSerializer();
serializer.reset();
try {
buf.append(serializer.serialize((NodeValue) next));
} catch (final SAXException e) {
throw (new XPathException(this, "An exception occurred while serializing node to log: " + e.getMessage(), e));
}
} else {
buf.append(next.getStringValue());
}
}
// Finally write the log
switch (calledAs) {
case FUNCTION_LOG:
final String loglevel = args[0].getStringValue().toLowerCase();
writeLog(buf, loglevel, logger);
break;
case FUNCTION_LOG_SYSTEM_OUT:
System.out.println(buf);
break;
case FUNCTION_LOG_SYSTEM_ERR:
System.err.println(buf);
break;
case FUNCTION_LOGAPP: {
final String loglevelapp = args[0].getStringValue().toLowerCase();
final String logname = args[1].getStringValue();
// Use specific logger when provided
final Logger logger = (logname == null || logname.isEmpty()) ? LOG : LogManager.getLogger(logname);
writeLog(buf, loglevelapp, logger);
break;
}
}
return (Sequence.EMPTY_SEQUENCE);
}
/**
* Write log message to logger with a priority.
*
* @param buffer The log text
* @param loglevel The priority of the log message
* @param logger The actual logger
*/
private void writeLog(final StringBuilder buffer, final String loglevel, final Logger logger) {
switch (loglevel) {
case "error":
logger.error(buffer);
break;
case "warn":
logger.warn(buffer);
break;
case "info":
logger.info(buffer);
break;
case "trace":
logger.trace(buffer);
break;
default:
logger.debug(buffer);
break;
}
}
}