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 */ 017 package org.apache.logging.log4j.core.appender.rewrite; 018 019 import org.apache.logging.log4j.Logger; 020 import org.apache.logging.log4j.core.LogEvent; 021 import org.apache.logging.log4j.core.config.plugins.Plugin; 022 import org.apache.logging.log4j.core.config.plugins.PluginAttr; 023 import org.apache.logging.log4j.core.config.plugins.PluginElement; 024 import org.apache.logging.log4j.core.config.plugins.PluginFactory; 025 import org.apache.logging.log4j.core.helpers.KeyValuePair; 026 import org.apache.logging.log4j.core.impl.Log4jLogEvent; 027 import org.apache.logging.log4j.message.MapMessage; 028 import org.apache.logging.log4j.message.Message; 029 import org.apache.logging.log4j.status.StatusLogger; 030 031 import java.util.HashMap; 032 import java.util.Map; 033 034 /** 035 * This policy modifies events by replacing or possibly adding keys and values to the MapMessage. 036 */ 037 @Plugin(name = "MapRewritePolicy", category = "Core", elementType = "rewritePolicy", printObject = true) 038 public final class MapRewritePolicy implements RewritePolicy { 039 /** 040 * Allow subclasses access to the status logger without creating another instance. 041 */ 042 protected static final Logger LOGGER = StatusLogger.getLogger(); 043 044 private final Map<String, String> map; 045 046 private final Mode mode; 047 048 private MapRewritePolicy(final Map<String, String> map, final Mode mode) { 049 this.map = map; 050 this.mode = mode; 051 } 052 053 /** 054 * Rewrite the event. 055 * @param source a logging event that may be returned or 056 * used to create a new logging event. 057 * @return The LogEvent after rewriting. 058 */ 059 @Override 060 public LogEvent rewrite(final LogEvent source) { 061 final Message msg = source.getMessage(); 062 if (msg == null || !(msg instanceof MapMessage)) { 063 return source; 064 } 065 066 final Map<String, String> newMap = new HashMap<String, String>(((MapMessage) msg).getData()); 067 switch (mode) { 068 case Add: { 069 newMap.putAll(map); 070 break; 071 } 072 default: { 073 for (final Map.Entry<String, String> entry : map.entrySet()) { 074 if (newMap.containsKey(entry.getKey())) { 075 newMap.put(entry.getKey(), entry.getValue()); 076 } 077 } 078 } 079 } 080 final MapMessage message = ((MapMessage) msg).newInstance(newMap); 081 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getFQCN(), source.getLevel(), 082 message, source.getThrown(), source.getContextMap(), source.getContextStack(), source.getThreadName(), 083 source.getSource(), source.getMillis()); 084 } 085 086 /** 087 * An enumeration to identify whether keys not in the MapMessage should be added or whether only existing 088 * keys should be updated. 089 */ 090 public enum Mode { 091 /** 092 * Keys should be added. 093 */ 094 Add, 095 /** 096 * Keys should be updated. 097 */ 098 Update 099 } 100 101 @Override 102 public String toString() { 103 final StringBuilder sb = new StringBuilder(); 104 sb.append("mode=").append(mode); 105 sb.append(" {"); 106 boolean first = true; 107 for (final Map.Entry<String, String> entry : map.entrySet()) { 108 if (!first) { 109 sb.append(", "); 110 } 111 sb.append(entry.getKey()).append("=").append(entry.getValue()); 112 first = false; 113 } 114 sb.append("}"); 115 return sb.toString(); 116 } 117 118 /** 119 * The factory method to create the MapRewritePolicy. 120 * @param mode The string representation of the Mode. 121 * @param pairs key/value pairs for the new Map keys and values. 122 * @return The MapRewritePolicy. 123 */ 124 @PluginFactory 125 public static MapRewritePolicy createPolicy(@PluginAttr("mode") final String mode, 126 @PluginElement("KeyValuePair") final KeyValuePair[] pairs) { 127 Mode op; 128 if (mode == null) { 129 op = Mode.Add; 130 } else { 131 op = Mode.valueOf(mode); 132 if (op == null) { 133 LOGGER.error("Undefined mode " + mode); 134 return null; 135 } 136 } 137 if (pairs == null || pairs.length == 0) { 138 LOGGER.error("keys and values must be specified for the MapRewritePolicy"); 139 return null; 140 } 141 final Map<String, String> map = new HashMap<String, String>(); 142 for (final KeyValuePair pair : pairs) { 143 final String key = pair.getKey(); 144 if (key == null) { 145 LOGGER.error("A null key is not valid in MapRewritePolicy"); 146 continue; 147 } 148 final String value = pair.getValue(); 149 if (value == null) { 150 LOGGER.error("A null value for key " + key + " is not allowed in MapRewritePolicy"); 151 continue; 152 } 153 map.put(pair.getKey(), pair.getValue()); 154 } 155 if (map.size() == 0) { 156 LOGGER.error("MapRewritePolicy is not configured with any valid key value pairs"); 157 return null; 158 } 159 return new MapRewritePolicy(map, op); 160 } 161 }