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.pattern; 018 019import java.util.Locale; 020 021import org.apache.logging.log4j.core.LogEvent; 022import org.apache.logging.log4j.core.config.Configuration; 023import org.apache.logging.log4j.core.config.plugins.Plugin; 024import org.apache.logging.log4j.core.util.ArrayUtils; 025import org.apache.logging.log4j.core.util.Constants; 026import org.apache.logging.log4j.core.util.Loader; 027import org.apache.logging.log4j.message.Message; 028import org.apache.logging.log4j.message.MultiformatMessage; 029import org.apache.logging.log4j.status.StatusLogger; 030import org.apache.logging.log4j.util.MultiFormatStringBuilderFormattable; 031import org.apache.logging.log4j.util.PerformanceSensitive; 032import org.apache.logging.log4j.util.StringBuilderFormattable; 033 034/** 035 * Returns the event's rendered message in a StringBuilder. 036 */ 037@Plugin(name = "MessagePatternConverter", category = PatternConverter.CATEGORY) 038@ConverterKeys({ "m", "msg", "message" }) 039@PerformanceSensitive("allocation") 040public final class MessagePatternConverter extends LogEventPatternConverter { 041 042 private static final String NOLOOKUPS = "nolookups"; 043 044 private final String[] formats; 045 private final Configuration config; 046 private final TextRenderer textRenderer; 047 048 /** 049 * Private constructor. 050 * 051 * @param options 052 * options, may be null. 053 */ 054 private MessagePatternConverter(final Configuration config, final String[] options) { 055 super("Message", "message"); 056 this.formats = options; 057 this.config = config; 058 final int noLookupsIdx = loadNoLookups(options); 059 this.textRenderer = loadMessageRenderer(noLookupsIdx >= 0 ? ArrayUtils.remove(options, noLookupsIdx) : options); 060 } 061 062 private int loadNoLookups(final String[] options) { 063 if (options != null) { 064 for (int i = 0; i < options.length; i++) { 065 final String option = options[i]; 066 if (NOLOOKUPS.equalsIgnoreCase(option)) { 067 return i; 068 } 069 } 070 } 071 return -1; 072 } 073 074 private TextRenderer loadMessageRenderer(final String[] options) { 075 if (options != null) { 076 for (final String option : options) { 077 switch (option.toUpperCase(Locale.ROOT)) { 078 case "ANSI": 079 if (Loader.isJansiAvailable()) { 080 return new JAnsiTextRenderer(options, JAnsiTextRenderer.DefaultMessageStyleMap); 081 } 082 StatusLogger.getLogger() 083 .warn("You requested ANSI message rendering but JANSI is not on the classpath."); 084 return null; 085 case "HTML": 086 return new HtmlTextRenderer(options); 087 } 088 } 089 } 090 return null; 091 } 092 093 /** 094 * Obtains an instance of pattern converter. 095 * 096 * @param config 097 * The Configuration. 098 * @param options 099 * 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}