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.layout; 018 019import org.apache.logging.log4j.Logger; 020import org.apache.logging.log4j.core.LogEvent; 021import org.apache.logging.log4j.core.config.Configuration; 022import org.apache.logging.log4j.core.config.Node; 023import org.apache.logging.log4j.core.config.plugins.Plugin; 024import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 025import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 026import org.apache.logging.log4j.core.config.plugins.PluginElement; 027import org.apache.logging.log4j.core.config.plugins.PluginFactory; 028import org.apache.logging.log4j.core.pattern.PatternFormatter; 029import org.apache.logging.log4j.core.pattern.PatternParser; 030import org.apache.logging.log4j.core.script.AbstractScript; 031import org.apache.logging.log4j.core.script.ScriptRef; 032import org.apache.logging.log4j.status.StatusLogger; 033 034import javax.script.SimpleBindings; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Map; 038 039/** 040 * Selects the pattern to use based on the Marker in the LogEvent. 041 */ 042@Plugin(name = "ScriptPatternSelector", category = Node.CATEGORY, elementType = PatternSelector.ELEMENT_TYPE, printObject = true) 043public class ScriptPatternSelector implements PatternSelector { 044 045 private final Map<String, PatternFormatter[]> formatterMap = new HashMap<>(); 046 047 private final Map<String, String> patternMap = new HashMap<>(); 048 049 private final PatternFormatter[] defaultFormatters; 050 051 private final String defaultPattern; 052 053 private static Logger LOGGER = StatusLogger.getLogger(); 054 private final AbstractScript script; 055 private final Configuration configuration; 056 057 058 public ScriptPatternSelector(final AbstractScript script, final PatternMatch[] properties, final String defaultPattern, 059 final boolean alwaysWriteExceptions, final boolean noConsoleNoAnsi, 060 final Configuration config) { 061 this.script = script; 062 this.configuration = config; 063 if (!(script instanceof ScriptRef)) { 064 config.getScriptManager().addScript(script); 065 } 066 final PatternParser parser = PatternLayout.createPatternParser(config); 067 for (PatternMatch property : properties) { 068 try { 069 List<PatternFormatter> list = parser.parse(property.getPattern(), alwaysWriteExceptions, noConsoleNoAnsi); 070 formatterMap.put(property.getKey(), list.toArray(new PatternFormatter[list.size()])); 071 patternMap.put(property.getKey(), property.getPattern()); 072 } catch (RuntimeException ex) { 073 throw new IllegalArgumentException("Cannot parse pattern '" + property.getPattern() + "'", ex); 074 } 075 } 076 try { 077 List<PatternFormatter> list = parser.parse(defaultPattern, alwaysWriteExceptions, noConsoleNoAnsi); 078 defaultFormatters = list.toArray(new PatternFormatter[list.size()]); 079 this.defaultPattern = defaultPattern; 080 } catch (RuntimeException ex) { 081 throw new IllegalArgumentException("Cannot parse pattern '" + defaultPattern + "'", ex); 082 } 083 } 084 085 @Override 086 public PatternFormatter[] getFormatters(LogEvent event) { 087 SimpleBindings bindings = new SimpleBindings(); 088 bindings.putAll(configuration.getProperties()); 089 bindings.put("substitutor", configuration.getStrSubstitutor()); 090 bindings.put("logEvent", event); 091 Object object = configuration.getScriptManager().execute(script.getName(), bindings); 092 if (object == null) { 093 return defaultFormatters; 094 } 095 PatternFormatter[] patternFormatter = formatterMap.get(object.toString()); 096 097 return patternFormatter == null ? defaultFormatters : patternFormatter; 098 } 099 100 101 @PluginFactory 102 public static ScriptPatternSelector createSelector(@PluginElement("Script") AbstractScript script, 103 @PluginElement("PatternMatch") final PatternMatch[] properties, 104 @PluginAttribute("defaultPattern") String defaultPattern, 105 @PluginAttribute(value = "alwaysWriteExceptions", defaultBoolean = true) final boolean alwaysWriteExceptions, 106 @PluginAttribute(value = "noConsoleNoAnsi", defaultBoolean = false) final boolean noConsoleNoAnsi, 107 @PluginConfiguration final Configuration config) { 108 if (script == null) { 109 LOGGER.error("A Script, ScriptFile or ScriptRef element must be provided for this ScriptFilter"); 110 return null; 111 } 112 if (script instanceof ScriptRef) { 113 if (config.getScriptManager().getScript(script.getName()) == null) { 114 LOGGER.error("No script with name {} has been declared.", script.getName()); 115 return null; 116 } 117 } 118 if (defaultPattern == null) { 119 defaultPattern = PatternLayout.DEFAULT_CONVERSION_PATTERN; 120 } 121 if (properties == null || properties.length == 0) { 122 LOGGER.warn("No marker patterns were provided"); 123 } 124 return new ScriptPatternSelector(script, properties, defaultPattern, alwaysWriteExceptions, noConsoleNoAnsi, config); 125 } 126 127 @Override 128 public String toString() { 129 StringBuilder sb = new StringBuilder(); 130 boolean first = true; 131 for (Map.Entry<String, String> entry : patternMap.entrySet()) { 132 if (!first) { 133 sb.append(", "); 134 } 135 sb.append("key=\"").append(entry.getKey()).append("\", pattern=\"").append(entry.getValue()).append("\""); 136 first = false; 137 } 138 if (!first) { 139 sb.append(", "); 140 } 141 sb.append("default=\"").append(defaultPattern).append("\""); 142 return sb.toString(); 143 } 144}