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.appender;
018
019import java.io.Serializable;
020import java.util.Objects;
021
022import javax.script.Bindings;
023
024import org.apache.logging.log4j.core.Appender;
025import org.apache.logging.log4j.core.Core;
026import org.apache.logging.log4j.core.Filter;
027import org.apache.logging.log4j.core.Layout;
028import org.apache.logging.log4j.core.LogEvent;
029import org.apache.logging.log4j.core.config.Configuration;
030import org.apache.logging.log4j.core.config.Property;
031import org.apache.logging.log4j.core.config.plugins.Plugin;
032import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
033import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
034import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
035import org.apache.logging.log4j.core.config.plugins.PluginElement;
036import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
037import org.apache.logging.log4j.core.script.AbstractScript;
038import org.apache.logging.log4j.core.script.ScriptManager;
039
040@Plugin(name = "ScriptAppenderSelector", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
041public class ScriptAppenderSelector extends AbstractAppender {
042
043    /**
044     * Builds an appender.
045     */
046    public static final class Builder implements org.apache.logging.log4j.core.util.Builder<Appender> {
047
048        @PluginElement("AppenderSet")
049        @Required
050        private AppenderSet appenderSet;
051
052        @PluginConfiguration
053        @Required
054        private Configuration configuration;
055
056        @PluginBuilderAttribute
057        @Required
058        private String name;
059
060        @PluginElement("Script")
061        @Required
062        private AbstractScript script;
063
064        @Override
065                public Appender build() {
066                        if (name == null) {
067                                LOGGER.error("Name missing.");
068                                return null;
069                        }
070                        if (script == null) {
071                                LOGGER.error("Script missing for ScriptAppenderSelector appender {}", name);
072                                return null;
073                        }
074                        if (appenderSet == null) {
075                                LOGGER.error("AppenderSet missing for ScriptAppenderSelector appender {}", name);
076                                return null;
077                        }
078                        if (configuration == null) {
079                                LOGGER.error("Configuration missing for ScriptAppenderSelector appender {}", name);
080                                return null;
081                        }
082                        final ScriptManager scriptManager = configuration.getScriptManager();
083                        scriptManager.addScript(script);
084                        final Bindings bindings = scriptManager.createBindings(script);
085                        LOGGER.debug("ScriptAppenderSelector '{}' executing {} '{}': {}", name, script.getLanguage(),
086                                        script.getName(), script.getScriptText());
087                        final Object object = scriptManager.execute(script.getName(), bindings);
088                        final String actualAppenderName = Objects.toString(object, null);
089                        LOGGER.debug("ScriptAppenderSelector '{}' selected '{}'", name, actualAppenderName);
090                        return appenderSet.createAppender(actualAppenderName, name);
091                }
092
093        public AppenderSet getAppenderSet() {
094            return appenderSet;
095        }
096
097        public Configuration getConfiguration() {
098            return configuration;
099        }
100
101        public String getName() {
102            return name;
103        }
104
105        public AbstractScript getScript() {
106            return script;
107        }
108
109        public Builder withAppenderNodeSet(@SuppressWarnings("hiding") final AppenderSet appenderSet) {
110            this.appenderSet = appenderSet;
111            return this;
112        }
113
114        public Builder withConfiguration(@SuppressWarnings("hiding") final Configuration configuration) {
115            this.configuration = configuration;
116            return this;
117        }
118
119        public Builder withName(@SuppressWarnings("hiding") final String name) {
120            this.name = name;
121            return this;
122        }
123
124        public Builder withScript(@SuppressWarnings("hiding") final AbstractScript script) {
125            this.script = script;
126            return this;
127        }
128
129    }
130
131    @PluginBuilderFactory
132    public static Builder newBuilder() {
133        return new Builder();
134    }
135
136    private ScriptAppenderSelector(final String name, final Filter filter, final Layout<? extends Serializable> layout,
137            final Property[] properties) {
138        super(name, filter, layout, true, Property.EMPTY_ARRAY);
139    }
140
141    @Override
142    public void append(final LogEvent event) {
143        // Do nothing: This appender is only used to discover and build another appender
144    }
145
146}