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