001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.filter;
018
019import javax.script.SimpleBindings;
020
021import org.apache.logging.log4j.Level;
022import org.apache.logging.log4j.Marker;
023import org.apache.logging.log4j.core.Filter;
024import org.apache.logging.log4j.core.LogEvent;
025import org.apache.logging.log4j.core.Logger;
026import org.apache.logging.log4j.core.config.Configuration;
027import org.apache.logging.log4j.core.config.Node;
028import org.apache.logging.log4j.core.config.plugins.Plugin;
029import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
030import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
031import org.apache.logging.log4j.core.config.plugins.PluginElement;
032import org.apache.logging.log4j.core.config.plugins.PluginFactory;
033import org.apache.logging.log4j.core.script.AbstractScript;
034import org.apache.logging.log4j.core.script.ScriptRef;
035import org.apache.logging.log4j.message.Message;
036import org.apache.logging.log4j.message.ObjectMessage;
037import org.apache.logging.log4j.message.SimpleMessage;
038import org.apache.logging.log4j.status.StatusLogger;
039
040/**
041 * Returns the onMatch result if the script returns True and returns the onMisMatch value otherwise.
042 */
043@Plugin(name = "ScriptFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
044public final class ScriptFilter extends AbstractFilter {
045
046    private static final long serialVersionUID = 1L;
047    private static org.apache.logging.log4j.Logger logger = StatusLogger.getLogger();
048
049    private final AbstractScript script;
050    private final Configuration configuration;
051
052    private ScriptFilter(final AbstractScript script, final Configuration configuration, final Result onMatch,
053                         final Result onMismatch) {
054        super(onMatch, onMismatch);
055        this.script = script;
056        this.configuration = configuration;
057        if (!(script instanceof ScriptRef)) {
058            configuration.getScriptManager().addScript(script);
059        }
060    }
061
062    @Override
063    public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
064                         final Object... params) {
065        SimpleBindings bindings = new SimpleBindings();
066        bindings.put("logger", logger);
067        bindings.put("level", level);
068        bindings.put("marker", marker);
069        bindings.put("message", new SimpleMessage(msg));
070        bindings.put("parameters", params);
071        bindings.put("throwable", null);
072        bindings.putAll(configuration.getProperties());
073        bindings.put("substitutor", configuration.getStrSubstitutor());
074        Object object = configuration.getScriptManager().execute(script.getName(), bindings);
075        return object == null || !Boolean.TRUE.equals(object) ? onMismatch : onMatch;
076    }
077
078    @Override
079    public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
080                         final Throwable t) {
081        SimpleBindings bindings = new SimpleBindings();
082        bindings.put("logger", logger);
083        bindings.put("level", level);
084        bindings.put("marker", marker);
085        bindings.put("message", msg instanceof String ? new SimpleMessage((String)msg) : new ObjectMessage(msg));
086        bindings.put("parameters", null);
087        bindings.put("throwable", t);
088        bindings.putAll(configuration.getProperties());
089        bindings.put("substitutor", configuration.getStrSubstitutor());
090        Object object = configuration.getScriptManager().execute(script.getName(), bindings);
091        return object == null || !Boolean.TRUE.equals(object) ? onMismatch : onMatch;
092    }
093
094    @Override
095    public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
096                         final Throwable t) {
097        SimpleBindings bindings = new SimpleBindings();
098        bindings.put("logger", logger);
099        bindings.put("level", level);
100        bindings.put("marker", marker);
101        bindings.put("message", msg);
102        bindings.put("parameters", null);
103        bindings.put("throwable", t);
104        bindings.putAll(configuration.getProperties());
105        bindings.put("substitutor", configuration.getStrSubstitutor());
106        Object object = configuration.getScriptManager().execute(script.getName(), bindings);
107        return object == null || !Boolean.TRUE.equals(object) ? onMismatch : onMatch;
108    }
109
110    @Override
111    public Result filter(final LogEvent event) {
112        SimpleBindings bindings = new SimpleBindings();
113        bindings.put("logEvent", event);
114        bindings.putAll(configuration.getProperties());
115        bindings.put("substitutor", configuration.getStrSubstitutor());
116        Object object = configuration.getScriptManager().execute(script.getName(), bindings);
117        return object == null || !Boolean.TRUE.equals(object) ? onMismatch : onMatch;
118    }
119
120    @Override
121    public String toString() {
122        return script.getName();
123    }
124
125    /**
126     * Creates the ScriptFilter.
127     * @param script The script to run. The script must return a boolean value. Either script or scriptFile must be 
128     *      provided.
129     * @param match The action to take if a match occurs.
130     * @param mismatch The action to take if no match occurs.
131     * @param configuration the configuration 
132     * @return A ScriptFilter.
133     */
134    @PluginFactory
135    public static ScriptFilter createFilter(
136            @PluginElement("Script") final AbstractScript script,
137            @PluginAttribute("onMatch") final Result match,
138            @PluginAttribute("onMismatch") final Result mismatch,
139            @PluginConfiguration final Configuration configuration) {
140
141        if (script == null) {
142            LOGGER.error("A Script, ScriptFile or ScriptRef element must be provided for this ScriptFilter");
143            return null;
144        }
145        if (script instanceof ScriptRef) {
146            if (configuration.getScriptManager().getScript(script.getName()) == null) {
147                logger.error("No script with name {} has been declared.", script.getName());
148                return null;
149            }
150        }
151
152        return new ScriptFilter(script, configuration, match, mismatch);
153    }
154
155}