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.pattern;
18  
19  import java.util.Locale;
20  
21  import org.apache.logging.log4j.core.LogEvent;
22  import org.apache.logging.log4j.core.config.Configuration;
23  import org.apache.logging.log4j.core.config.plugins.Plugin;
24  import org.apache.logging.log4j.core.util.ArrayUtils;
25  import org.apache.logging.log4j.core.util.Constants;
26  import org.apache.logging.log4j.core.util.Loader;
27  import org.apache.logging.log4j.message.Message;
28  import org.apache.logging.log4j.message.MultiformatMessage;
29  import org.apache.logging.log4j.status.StatusLogger;
30  import org.apache.logging.log4j.util.MultiFormatStringBuilderFormattable;
31  import org.apache.logging.log4j.util.PerformanceSensitive;
32  import org.apache.logging.log4j.util.StringBuilderFormattable;
33  
34  /**
35   * Returns the event's rendered message in a StringBuilder.
36   */
37  @Plugin(name = "MessagePatternConverter", category = PatternConverter.CATEGORY)
38  @ConverterKeys({ "m", "msg", "message" })
39  @PerformanceSensitive("allocation")
40  public final class MessagePatternConverter extends LogEventPatternConverter {
41  
42      private static final String NOLOOKUPS = "nolookups";
43  
44      private final String[] formats;
45      private final Configuration config;
46      private final TextRenderer textRenderer;
47  
48      /**
49       * Private constructor.
50       *
51       * @param options
52       *            options, may be null.
53       */
54      private MessagePatternConverter(final Configuration config, final String[] options) {
55          super("Message", "message");
56          this.formats = options;
57          this.config = config;
58          final int noLookupsIdx = loadNoLookups(options);
59          this.textRenderer = loadMessageRenderer(noLookupsIdx >= 0 ? ArrayUtils.remove(options, noLookupsIdx) : options);
60      }
61  
62      private int loadNoLookups(final String[] options) {
63          if (options != null) {
64              for (int i = 0; i < options.length; i++) {
65                  final String option = options[i];
66                  if (NOLOOKUPS.equalsIgnoreCase(option)) {
67                      return i;
68                  }
69              }
70          }
71          return -1;
72      }
73  
74      private TextRenderer loadMessageRenderer(final String[] options) {
75          if (options != null) {
76              for (final String option : options) {
77                  switch (option.toUpperCase(Locale.ROOT)) {
78                  case "ANSI":
79                      if (Loader.isJansiAvailable()) {
80                          return new JAnsiTextRenderer(options, JAnsiTextRenderer.DefaultMessageStyleMap);
81                      }
82                      StatusLogger.getLogger()
83                              .warn("You requested ANSI message rendering but JANSI is not on the classpath.");
84                      return null;
85                  case "HTML":
86                      return new HtmlTextRenderer(options);
87                  }
88              }
89          }
90          return null;
91      }
92  
93      /**
94       * Obtains an instance of pattern converter.
95       *
96       * @param config
97       *            The Configuration.
98       * @param options
99       *            options, may be null.
100      * @return instance of pattern converter.
101      */
102     public static MessagePatternConverter newInstance(final Configuration config, final String[] options) {
103         return new MessagePatternConverter(config, options);
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
110     public void format(final LogEvent event, final StringBuilder toAppendTo) {
111         final Message msg = event.getMessage();
112         if (msg instanceof StringBuilderFormattable) {
113 
114             final boolean doRender = textRenderer != null;
115             final StringBuilder workingBuilder = doRender ? new StringBuilder(80) : toAppendTo;
116 
117             if (msg instanceof MultiFormatStringBuilderFormattable) {
118                 ((MultiFormatStringBuilderFormattable) msg).formatTo(formats, workingBuilder);
119             } else {
120                 ((StringBuilderFormattable) msg).formatTo(workingBuilder);
121             }
122 
123             if (doRender) {
124                 textRenderer.render(workingBuilder, toAppendTo);
125             }
126             return;
127         }
128         if (msg != null) {
129             String result;
130             if (msg instanceof MultiformatMessage) {
131                 result = ((MultiformatMessage) msg).getFormattedMessage(formats);
132             } else {
133                 result = msg.getFormattedMessage();
134             }
135             if (result != null) {
136                 toAppendTo.append(result);
137             } else {
138                 toAppendTo.append("null");
139             }
140         }
141     }
142 }