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<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 if (source instanceof Log4jLogEvent) { 082 final Log4jLogEvent event = (Log4jLogEvent) source; 083 return Log4jLogEvent.createEvent(event.getLoggerName(), event.getMarker(), event.getLoggerFqcn(), 084 event.getLevel(), message, event.getThrown(), event.getThrownProxy(), event.getContextMap(), 085 event.getContextStack(), event.getThreadName(), event.getSource(), event.getTimeMillis()); 086 } 087 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getLoggerFqcn(), source.getLevel(), 088 message, source.getThrown(), source.getContextMap(), source.getContextStack(), source.getThreadName(), 089 source.getSource(), source.getTimeMillis()); 090 } 091 092 /** 093 * An enumeration to identify whether keys not in the MapMessage should be added or whether only existing 094 * keys should be updated. 095 */ 096 public enum Mode { 097 /** 098 * Keys should be added. 099 */ 100 Add, 101 /** 102 * Keys should be updated. 103 */ 104 Update 105 } 106 107 @Override 108 public String toString() { 109 final StringBuilder sb = new StringBuilder(); 110 sb.append("mode=").append(mode); 111 sb.append(" {"); 112 boolean first = true; 113 for (final Map.Entry<String, String> entry : map.entrySet()) { 114 if (!first) { 115 sb.append(", "); 116 } 117 sb.append(entry.getKey()).append('=').append(entry.getValue()); 118 first = false; 119 } 120 sb.append('}'); 121 return sb.toString(); 122 } 123 124 /** 125 * The factory method to create the MapRewritePolicy. 126 * @param mode The string representation of the Mode. 127 * @param pairs key/value pairs for the new Map keys and values. 128 * @return The MapRewritePolicy. 129 */ 130 @PluginFactory 131 public static MapRewritePolicy createPolicy( 132 @PluginAttribute("mode") final String mode, 133 @PluginElement("KeyValuePair") final KeyValuePair[] pairs) { 134 Mode op; 135 if (mode == null) { 136 op = Mode.Add; 137 } else { 138 op = Mode.valueOf(mode); 139 if (op == null) { 140 LOGGER.error("Undefined mode " + mode); 141 return null; 142 } 143 } 144 if (pairs == null || pairs.length == 0) { 145 LOGGER.error("keys and values must be specified for the MapRewritePolicy"); 146 return null; 147 } 148 final Map<String, String> map = new HashMap<String, String>(); 149 for (final KeyValuePair pair : pairs) { 150 final String key = pair.getKey(); 151 if (key == null) { 152 LOGGER.error("A null key is not valid in MapRewritePolicy"); 153 continue; 154 } 155 final String value = pair.getValue(); 156 if (value == null) { 157 LOGGER.error("A null value for key " + key + " is not allowed in MapRewritePolicy"); 158 continue; 159 } 160 map.put(pair.getKey(), pair.getValue()); 161 } 162 if (map.isEmpty()) { 163 LOGGER.error("MapRewritePolicy is not configured with any valid key value pairs"); 164 return null; 165 } 166 return new MapRewritePolicy(map, op); 167 } 168}