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", type = "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 public LogEvent rewrite(final LogEvent source) { 060 final Message msg = source.getMessage(); 061 if (msg == null || !(msg instanceof MapMessage)) { 062 return source; 063 } 064 065 final Map<String, String> newMap = new HashMap<String, String>(((MapMessage) msg).getData()); 066 switch (mode) { 067 case Add: { 068 newMap.putAll(map); 069 break; 070 } 071 default: { 072 for (final Map.Entry<String, String> entry : map.entrySet()) { 073 if (newMap.containsKey(entry.getKey())) { 074 newMap.put(entry.getKey(), entry.getValue()); 075 } 076 } 077 } 078 } 079 final MapMessage message = ((MapMessage) msg).newInstance(newMap); 080 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getFQCN(), source.getLevel(), 081 message, source.getThrown(), source.getContextMap(), source.getContextStack(), source.getThreadName(), 082 source.getSource(), source.getMillis()); 083 } 084 085 /** 086 * An enumeration to identify whether keys not in the MapMessage should be added or whether only existing 087 * keys should be updated. 088 */ 089 public enum Mode { 090 /** 091 * Keys should be added. 092 */ 093 Add, 094 /** 095 * Keys should be updated. 096 */ 097 Update 098 } 099 100 @Override 101 public String toString() { 102 final StringBuilder sb = new StringBuilder(); 103 sb.append("mode=").append(mode); 104 sb.append(" {"); 105 boolean first = true; 106 for (final Map.Entry<String, String> entry : map.entrySet()) { 107 if (!first) { 108 sb.append(", "); 109 } 110 sb.append(entry.getKey()).append("=").append(entry.getValue()); 111 first = false; 112 } 113 sb.append("}"); 114 return sb.toString(); 115 } 116 117 /** 118 * The factory method to create the MapRewritePolicy. 119 * @param mode The string representation of the Mode. 120 * @param pairs key/value pairs for the new Map keys and values. 121 * @return The MapRewritePolicy. 122 */ 123 @PluginFactory 124 public static MapRewritePolicy createPolicy(@PluginAttr("mode") final String mode, 125 @PluginElement("KeyValuePair") final KeyValuePair[] pairs) { 126 Mode op; 127 if (mode == null) { 128 op = Mode.Add; 129 } else { 130 op = Mode.valueOf(mode); 131 if (op == null) { 132 LOGGER.error("Undefined mode " + mode); 133 return null; 134 } 135 } 136 if (pairs == null || pairs.length == 0) { 137 LOGGER.error("keys and values must be specified for the MapRewritePolicy"); 138 return null; 139 } 140 final Map<String, String> map = new HashMap<String, String>(); 141 for (final KeyValuePair pair : pairs) { 142 final String key = pair.getKey(); 143 if (key == null) { 144 LOGGER.error("A null key is not valid in MapRewritePolicy"); 145 continue; 146 } 147 final String value = pair.getValue(); 148 if (value == null) { 149 LOGGER.error("A null value for key " + key + " is not allowed in MapRewritePolicy"); 150 continue; 151 } 152 map.put(pair.getKey(), pair.getValue()); 153 } 154 if (map.size() == 0) { 155 LOGGER.error("MapRewritePolicy is not configured with any valid key value pairs"); 156 return null; 157 } 158 return new MapRewritePolicy(map, op); 159 } 160 }