View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.appender.rewrite;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import org.apache.logging.log4j.Logger;
23  import org.apache.logging.log4j.core.Core;
24  import org.apache.logging.log4j.core.LogEvent;
25  import org.apache.logging.log4j.core.config.plugins.Plugin;
26  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
27  import org.apache.logging.log4j.core.config.plugins.PluginElement;
28  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
29  import org.apache.logging.log4j.core.impl.Log4jLogEvent;
30  import org.apache.logging.log4j.core.util.KeyValuePair;
31  import org.apache.logging.log4j.message.MapMessage;
32  import org.apache.logging.log4j.message.Message;
33  import org.apache.logging.log4j.status.StatusLogger;
34  
35  /**
36   * This policy modifies events by replacing or possibly adding keys and values to the MapMessage.
37   */
38  @Plugin(name = "MapRewritePolicy", category = Core.CATEGORY_NAME, elementType = "rewritePolicy", printObject = true)
39  public final class MapRewritePolicy implements RewritePolicy {
40      /**
41       * Allow subclasses access to the status logger without creating another instance.
42       */
43      protected static final Logger LOGGER = StatusLogger.getLogger();
44  
45      private final Map<String, Object> map;
46  
47      private final Mode mode;
48  
49      private MapRewritePolicy(final Map<String, Object> map, final Mode mode) {
50          this.map = map;
51          this.mode = mode;
52      }
53  
54      /**
55       * Rewrite the event.
56       * @param source a logging event that may be returned or
57       * used to create a new logging event.
58       * @return The LogEvent after rewriting.
59       */
60      @Override
61      public LogEvent rewrite(final LogEvent source) {
62          final Message msg = source.getMessage();
63          if (msg == null || !(msg instanceof MapMessage)) {
64              return source;
65          }
66  
67          @SuppressWarnings("unchecked")
68          final MapMessage<?, Object> mapMsg = (MapMessage<?, Object>) msg;
69          final Map<String, Object> newMap = new HashMap<>(mapMsg.getData());
70          switch (mode) {
71              case Add: {
72                  newMap.putAll(map);
73                  break;
74              }
75              default: {
76                  for (final Map.Entry<String, Object> entry : map.entrySet()) {
77                      if (newMap.containsKey(entry.getKey())) {
78                          newMap.put(entry.getKey(), entry.getValue());
79                      }
80                  }
81              }
82          }
83          final Message message = mapMsg.newInstance(newMap);
84          final LogEvent result = new Log4jLogEvent.Builder(source).setMessage(message).build();
85          return result;
86      }
87  
88      /**
89       * An enumeration to identify whether keys not in the MapMessage should be added or whether only existing
90       * keys should be updated.
91       */
92      public enum Mode {
93          /**
94           * Keys should be added.
95           */
96          Add,
97          /**
98           * Keys should be updated.
99           */
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 }