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.LogEvent; 024import org.apache.logging.log4j.core.config.plugins.Plugin; 025import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 026import org.apache.logging.log4j.core.config.plugins.PluginElement; 027import org.apache.logging.log4j.core.config.plugins.PluginFactory; 028import org.apache.logging.log4j.core.impl.Log4jLogEvent; 029import org.apache.logging.log4j.core.util.KeyValuePair; 030import org.apache.logging.log4j.message.MapMessage; 031import org.apache.logging.log4j.message.Message; 032import org.apache.logging.log4j.status.StatusLogger; 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) 038public 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<>(((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 final LogEvent result = new Log4jLogEvent.Builder(source).setMessage(message).build(); 082 return result; 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( 125 @PluginAttribute("mode") final String mode, 126 @PluginElement("KeyValuePair") final KeyValuePair[] pairs) { 127 Mode op = mode == null ? op = Mode.Add : Mode.valueOf(mode); 128 if (pairs == null || pairs.length == 0) { 129 LOGGER.error("keys and values must be specified for the MapRewritePolicy"); 130 return null; 131 } 132 final Map<String, String> map = new HashMap<>(); 133 for (final KeyValuePair pair : pairs) { 134 final String key = pair.getKey(); 135 if (key == null) { 136 LOGGER.error("A null key is not valid in MapRewritePolicy"); 137 continue; 138 } 139 final String value = pair.getValue(); 140 if (value == null) { 141 LOGGER.error("A null value for key " + key + " is not allowed in MapRewritePolicy"); 142 continue; 143 } 144 map.put(pair.getKey(), pair.getValue()); 145 } 146 if (map.isEmpty()) { 147 LOGGER.error("MapRewritePolicy is not configured with any valid key value pairs"); 148 return null; 149 } 150 return new MapRewritePolicy(map, op); 151 } 152}