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.LogEvent;
24  import org.apache.logging.log4j.core.config.plugins.Plugin;
25  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
26  import org.apache.logging.log4j.core.config.plugins.PluginElement;
27  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
28  import org.apache.logging.log4j.core.impl.Log4jLogEvent;
29  import org.apache.logging.log4j.core.util.KeyValuePair;
30  import org.apache.logging.log4j.message.MapMessage;
31  import org.apache.logging.log4j.message.Message;
32  import org.apache.logging.log4j.status.StatusLogger;
33  
34  /**
35   * This policy modifies events by replacing or possibly adding keys and values to the MapMessage.
36   */
37  @Plugin(name = "MapRewritePolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
38  public final class MapRewritePolicy implements RewritePolicy {
39      /**
40       * Allow subclasses access to the status logger without creating another instance.
41       */
42      protected static final Logger LOGGER = StatusLogger.getLogger();
43  
44      private final Map<String, String> map;
45  
46      private final Mode mode;
47  
48      private MapRewritePolicy(final Map<String, String> map, final Mode mode) {
49          this.map = map;
50          this.mode = mode;
51      }
52  
53      /**
54       * Rewrite the event.
55       * @param source a logging event that may be returned or
56       * used to create a new logging event.
57       * @return The LogEvent after rewriting.
58       */
59      @Override
60      public LogEvent rewrite(final LogEvent source) {
61          final Message msg = source.getMessage();
62          if (msg == null || !(msg instanceof MapMessage)) {
63              return source;
64          }
65  
66          final Map<String, String> newMap = new HashMap<String, String>(((MapMessage) msg).getData());
67          switch (mode) {
68              case Add: {
69                  newMap.putAll(map);
70                  break;
71              }
72              default: {
73                  for (final Map.Entry<String, String> entry : map.entrySet()) {
74                      if (newMap.containsKey(entry.getKey())) {
75                          newMap.put(entry.getKey(), entry.getValue());
76                      }
77                  }
78              }
79          }
80          final MapMessage message = ((MapMessage) msg).newInstance(newMap);
81          if (source instanceof Log4jLogEvent) {
82              final Log4jLogEvent event = (Log4jLogEvent) source;
83              return Log4jLogEvent.createEvent(event.getLoggerName(), event.getMarker(), event.getLoggerFqcn(),
84                  event.getLevel(), message, event.getThrown(), event.getThrownProxy(), event.getContextMap(), 
85                  event.getContextStack(), event.getThreadName(), event.getSource(), event.getTimeMillis());
86          }
87          return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
88              message, source.getThrown(), source.getContextMap(), source.getContextStack(), source.getThreadName(),
89              source.getSource(), source.getTimeMillis());
90      }
91  
92      /**
93       * An enumeration to identify whether keys not in the MapMessage should be added or whether only existing
94       * keys should be updated.
95       */
96      public enum Mode {
97          /**
98           * Keys should be added.
99           */
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 }