logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Roger Kapsi (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (LOG4J2-1531) Change attribute and component values from String to Object
Date Fri, 19 Aug 2016 21:02:20 GMT

    [ 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: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org


Mime
View raw message