| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.log4j.spi; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import org.apache.log4j.chainsaw.logevents.ChainsawLoggingEvent; |
| import org.apache.log4j.rule.InFixToPostFix; |
| |
| /** |
| * A singleton helper utility which accepts a field name |
| * and a LoggingEvent and returns the value of that field. |
| * |
| * This class defines a grammar used in creation of an expression-based Rule. |
| * |
| * The only available method is |
| * Object getField(String fieldName, LoggingEvent event). |
| * |
| * Here is a description of the mapping of field names in the grammar |
| * to fields on the logging event. While the getField method returns an Object, |
| * the individual types returned per field are described here: |
| * |
| * Field Name Field value (String representation Return type |
| * LOGGER category name (logger) String |
| * LEVEL level Level |
| * CLASS locationInformation's class name String |
| * FILE locationInformation's file name String |
| * LINE locationInformation's line number String |
| * METHOD locationInformation's method name String |
| * MSG message Object |
| * NDC NDC String |
| * EXCEPTION throwable string representation ThrowableInformation |
| * TIMESTAMP timestamp Long |
| * THREAD thread String |
| * PROP.keyName entry in the Property hashtable String |
| * mapped to the key [keyName] |
| * |
| * NOTE: the values for the 'keyName' portion of the MDC and PROP mappings must |
| * be an exact match to the key in the hashTable (case sensitive). |
| * |
| * If the passed-in field is null or doesn't match an entry |
| * in the above-described mapping, an exception is thrown. |
| * |
| * @author Scott Deboy (sdeboy@apache.org) |
| * @author Paul Smith (psmith@apache.org) |
| * |
| */ |
| public final class LoggingEventFieldResolver { |
| /** |
| * Keyword list. |
| */ |
| public static final List KEYWORD_LIST = new ArrayList(); |
| /** |
| * LOGGER string literal. |
| */ |
| public static final String LOGGER_FIELD = "LOGGER"; |
| /** |
| * LEVEL string literal. |
| */ |
| public static final String LEVEL_FIELD = "LEVEL"; |
| /** |
| * CLASS string literal. |
| */ |
| public static final String CLASS_FIELD = "CLASS"; |
| /** |
| * FILE string literal. |
| */ |
| public static final String FILE_FIELD = "FILE"; |
| /** |
| * LINE string literal. |
| */ |
| public static final String LINE_FIELD = "LINE"; |
| /** |
| * METHOD string literal. |
| */ |
| public static final String METHOD_FIELD = "METHOD"; |
| /** |
| * MSG string literal. |
| */ |
| public static final String MSG_FIELD = "MSG"; |
| /** |
| * NDC string literal. |
| */ |
| public static final String NDC_FIELD = "NDC"; |
| /** |
| * EXCEPTION string literal. |
| */ |
| public static final String EXCEPTION_FIELD = "EXCEPTION"; |
| /** |
| * TIMESTAMP string literal. |
| */ |
| public static final String TIMESTAMP_FIELD = "TIMESTAMP"; |
| /** |
| * THREAD string literal. |
| */ |
| public static final String THREAD_FIELD = "THREAD"; |
| /** |
| * PROP. string literal. |
| */ |
| public static final String PROP_FIELD = "PROP."; |
| /** |
| * empty string literal. |
| */ |
| public static final String EMPTY_STRING = ""; |
| /** |
| * LOGGER string literal. |
| */ |
| private static final LoggingEventFieldResolver RESOLVER = new LoggingEventFieldResolver(); |
| |
| /** |
| * Create new instance. |
| */ |
| private LoggingEventFieldResolver() { |
| super(); |
| KEYWORD_LIST.add(LOGGER_FIELD); |
| KEYWORD_LIST.add(LEVEL_FIELD); |
| KEYWORD_LIST.add(CLASS_FIELD); |
| KEYWORD_LIST.add(FILE_FIELD); |
| KEYWORD_LIST.add(LINE_FIELD); |
| KEYWORD_LIST.add(METHOD_FIELD); |
| KEYWORD_LIST.add(MSG_FIELD); |
| KEYWORD_LIST.add(NDC_FIELD); |
| KEYWORD_LIST.add(EXCEPTION_FIELD); |
| KEYWORD_LIST.add(TIMESTAMP_FIELD); |
| KEYWORD_LIST.add(THREAD_FIELD); |
| KEYWORD_LIST.add(PROP_FIELD); |
| } |
| |
| /** |
| * Apply fields. |
| * @param replaceText replacement text. |
| * @param event logging event. |
| * @return evaluted expression |
| */ |
| public String applyFields(final String replaceText, final ChainsawLoggingEvent event) { |
| if (replaceText == null) { |
| return null; |
| } |
| InFixToPostFix.CustomTokenizer tokenizer = new InFixToPostFix.CustomTokenizer(replaceText); |
| StringBuffer result = new StringBuffer(); |
| boolean found = false; |
| |
| while (tokenizer.hasMoreTokens()) { |
| String token = tokenizer.nextToken(); |
| if (isField(token) || token.toUpperCase(Locale.US).startsWith(PROP_FIELD)) { |
| result.append(getValue(token, event).toString()); |
| found = true; |
| } else { |
| result.append(token); |
| } |
| } |
| if (found) { |
| return result.toString(); |
| } |
| return null; |
| } |
| |
| /** |
| * Get singleton instance. |
| * @return singleton instance |
| */ |
| public static LoggingEventFieldResolver getInstance() { |
| return RESOLVER; |
| } |
| |
| /** |
| * Determines if specified string is a recognized field. |
| * @param fieldName field name |
| * @return true if recognized field. |
| */ |
| public boolean isField(final String fieldName) { |
| if (fieldName != null) { |
| return (KEYWORD_LIST.contains(fieldName.toUpperCase(Locale.US)) |
| || fieldName.toUpperCase().startsWith(PROP_FIELD)); |
| } |
| return false; |
| } |
| |
| /** |
| * Get value of field. |
| * @param fieldName field |
| * @param event event |
| * @return value of field |
| */ |
| public Object getValue(final String fieldName, final ChainsawLoggingEvent event) { |
| String upperField = fieldName.toUpperCase(Locale.US); |
| if (LOGGER_FIELD.equals(upperField)) { |
| return event.m_logger; |
| } else if (LEVEL_FIELD.equals(upperField)) { |
| return event.m_level; |
| } else if (MSG_FIELD.equals(upperField)) { |
| return event.m_message; |
| } else if (NDC_FIELD.equals(upperField)) { |
| String ndcValue = event.m_ndc; |
| return ((ndcValue == null) ? EMPTY_STRING : ndcValue); |
| } else if (EXCEPTION_FIELD.equals(upperField)) { |
| // String[] throwableRep = event.getThrowableStrRep(); |
| // if (throwableRep == null) { |
| // return EMPTY_STRING; |
| // } else { |
| // return getExceptionMessage(throwableRep); |
| // } |
| return ""; |
| } else if (TIMESTAMP_FIELD.equals(upperField)) { |
| return event.m_timestamp; |
| } else if (THREAD_FIELD.equals(upperField)) { |
| return event.m_threadName; |
| } else if (upperField.startsWith(PROP_FIELD)) { |
| // note: need to use actual fieldname since case matters |
| String realFieldName = fieldName.substring(5); |
| String property = event.getProperty(realFieldName); |
| if (property != null && property.length() >= 1) { |
| return property; |
| } |
| |
| // We did not get the property in a case-sensitive manner - check for |
| // case-insensitive |
| for (Map.Entry<String, String> entry : event.getProperties().entrySet()) { |
| if (entry.getKey().equalsIgnoreCase(realFieldName)) { |
| return entry.getValue(); |
| } |
| } |
| |
| return EMPTY_STRING; |
| } else { |
| org.apache.log4j.chainsaw.logevents.LocationInfo info = event.m_locationInfo; |
| if (CLASS_FIELD.equals(upperField)) { |
| return ((info == null) ? EMPTY_STRING : info.className); |
| } else if (FILE_FIELD.equals(upperField)) { |
| return ((info == null) ? EMPTY_STRING : info.fileName); |
| } else if (LINE_FIELD.equals(upperField)) { |
| return ((info == null) ? EMPTY_STRING : info.lineNumber); |
| } else if (METHOD_FIELD.equals(upperField)) { |
| return ((info == null) ? EMPTY_STRING : info.methodName); |
| } |
| } |
| |
| // there wasn't a match, so throw a runtime exception |
| throw new IllegalArgumentException("Unsupported field name: " + fieldName); |
| } |
| |
| /** |
| * Get message from throwable representation. |
| * @param exception exception |
| * @return message |
| */ |
| private static String getExceptionMessage(final String[] exception) { |
| StringBuffer buff = new StringBuffer(); |
| for (int i = 0; i < exception.length; i++) { |
| buff.append(exception[i]); |
| } |
| return buff.toString(); |
| } |
| } |