[
https://issues.apache.org/jira/browse/LOG4J2-1531?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15428806#comment-15428806
]
Roger Kapsi commented on LOG4J2-1531:
-------------------------------------
That doesn't quite cut it. Because Java 7 doesn't have lambda functions I had
to fake it and keep it simple. Hence the one arg but somewhat useless function.
I also don't want to narrow it down to just filters. That stuff is equally
applicable to appenders, layout and everything else.
Here's one more try to explain it from the DSL's point of view.
{code}
(configuration
(appender "out" "CONSOLE"
(layout "ClojureLayout"
(argument "fn" (fn [msg]
(replace msg #"Hello, World!" "Hack the
Planet!")))))
(filter "ClojureFilter" "DENY" "NEUTRAL"
(argument "fn" (fn [logger level marker msg & more]
(and (= (.getName logger) "org.apache.MyClass")
(= level Level/ERROR)
(and (not (nil? msg))
(.contains msg "Hello, World!")))))))
{code}
{code:java}
@Plugin(name = "ClojureFilter", category = Node.CATEGORY, elementType =
Filter.ELEMENT_TYPE, printObject = true)
public final class ClojureFilter extends AbstractFilter {
private static final Logger LOG = StatusLogger.getLogger();
/**
* Clojure's {@link IFn#invoke()} method takes up to 20 arguments without
using {@code varargs}. That's great but
* requires us to do some extra work as seen in {@link
#invoke(org.apache.logging.log4j.core.Logger, Level, Marker, String, Object...)}
*/
private static final int MAX_INVOKE_ARGS = 20;
/**
* @see #MAX_INVOKE_ARGS
*/
private static final int MIN_INVOKE_ARGS = 4;
/**
* @see #MAX_INVOKE_ARGS
*/
private static final int MAX_PARAM_INVOKE_ARGS = MAX_INVOKE_ARGS -
MIN_INVOKE_ARGS;
@PluginFactory
public static ClojureFilter createFilter(
@PluginArgument("fn") IFn fn,
@PluginAttribute("onMatch") Result match,
@PluginAttribute("onMismatch") Result mismatch) {
if (fn == null) {
LOG.error("A fn must be provided for this ClojureFilter");
return null;
}
if (!(fn instanceof IFn)) {
LOG.error("The 'fn' attribute must be an IFn: " + fn + ", " +
fn.getClass());
return null;
}
return new ClojureFilter((IFn)fn, match, mismatch);
}
private final IFn fn;
private ClojureFilter(IFn fn, Result match, Result mismatch) {
super(match, mismatch);
this.fn = fn;
}
private Result toResult(Object value) {
return value == null || !Boolean.TRUE.equals(value) ? onMismatch : onMatch;
}
@Override
public Result filter(LogEvent event) {
Object value = fn.invoke(event);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, Message msg,
Throwable t) {
Object value = fn.invoke(logger, level, marker, msg, t);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, Object msg,
Throwable t) {
Object value = fn.invoke(logger, level, marker, msg, t);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0) {
Object value = fn.invoke(logger, level, marker, msg, p0);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4, Object p5) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4,
p5);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4,
p5, p6);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object
p7) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4,
p5, p6, p7);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object
p7, Object p8) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4,
p5, p6, p7, p8);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg, Object p0,
Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object
p7, Object p8, Object p9) {
Object value = fn.invoke(logger, level, marker, msg, p0, p1, p2, p3, p4,
p5, p6, p7, p8, p9);
return toResult(value);
}
@Override
public Result filter(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg,
Object... params) {
Object value = invoke(logger, level, marker, msg, params);
return toResult(value);
}
private Object invoke(org.apache.logging.log4j.core.Logger logger, Level
level, Marker marker, String msg,
Object... params) {
if (params == null) {
return fn.invoke(logger, level, marker, msg);
}
switch (params.length) {
case 0:
return fn.invoke(logger, level, marker, msg);
case 1:
return fn.invoke(logger, level, marker, msg, params[0]);
case 2:
return fn.invoke(logger, level, marker, msg, params[0], params[1]);
case 3:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2]);
case 4:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3]);
case 5:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4]);
case 6:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5]);
case 7:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6]);
case 8:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7]);
case 9:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8]);
case 10:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9]);
case 11:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10]);
case 12:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11]);
case 13:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11],
params[12]);
case 14:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11],
params[12], params[13]);
case 15:
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11],
params[12], params[13], params[14]);
case 16:
// logger+level+marker+msg = 4 + 16 params = 20 arguments
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11],
params[12], params[13], params[14],
params[15]);
default:
Object[] reminder = new Object[params.length-MAX_PARAM_INVOKE_ARGS];
System.arraycopy(params, MAX_PARAM_INVOKE_ARGS, reminder, 0,
reminder.length);
return fn.invoke(logger, level, marker, msg, params[0], params[1],
params[2], params[3], params[4], params[5],
params[6], params[7], params[8], params[9], params[10], params[11],
params[12], params[13], params[14],
params[15], reminder);
}
}
@Override
public String toString() {
return Objects.toString(fn);
}
}
{code}
> Change attribute and component values from String to Object
> -----------------------------------------------------------
>
> Key: LOG4J2-1531
> URL: https://issues.apache.org/jira/browse/LOG4J2-1531
> Project: Log4j 2
> Issue Type: Improvement
> Components: Core
> Affects Versions: 2.6.2
> Reporter: Roger Kapsi
> Attachments: log4j2-1531-1.0.patch
>
>
> I was looking into creating a ConfigurationFactory/Builder that is backed by
> a Clojure DSL. It works rather beautifully until I tried to create a filter
> that is backed by a Clojure function. There is literally no way to pass
> arbitrary objects into a PluginFactory. All component values and attributes
> are assumed to be Strings.
> {code:java}
> (configuration
> (appender "stdout" "CONSOLE"
> (layout "PatternLayout"
> (attribute "pattern" "%d [%t] %-5level: %msg%n"))
> (filter "ClojureFilter"
> ;; This LoC doesn't work: addAttribute(key, value)
> ;; will store the toString() of the value. Bummer.
> ;; I'd the so easy and beautiful if it didn't.
> (attribute "fn" (fn [logger & more] (println logger)))))
>
> (logger "TestLogger" Level/INFO
> (appender-ref "rolling")
> (attribute "additivity" false))
> (root-logger Level/DEBUG
> (appender-ref "rolling")))
> {code}
> {code:java}
> @Plugin(name = "ClojureFilter", category = Node.CATEGORY, elementType =
> Filter.ELEMENT_TYPE, printObject = true)
> class ClojureFilter extends AbstractFilter {
> @PluginFactory
> public static ClojureFilter createFilter(
> @PluginAttribute("fn") IFn fn, ...) {
> return new ClojureFilter(fn, ...);
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]