1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.spi;
19
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.Locale;
26
27 import org.apache.log4j.rule.InFixToPostFix;
28
29
30 /***
31 * A singleton helper utility which accepts a field name
32 * and a LoggingEvent and returns the value of that field.
33 *
34 * This class defines a grammar used in creation of an expression-based Rule.
35 *
36 * The only available method is
37 * Object getField(String fieldName, LoggingEvent event).
38 *
39 * Here is a description of the mapping of field names in the grammar
40 * to fields on the logging event. While the getField method returns an Object,
41 * the individual types returned per field are described here:
42 *
43 * Field Name Field value (String representation Return type
44 * LOGGER category name (logger) String
45 * LEVEL level Level
46 * CLASS locationInformation's class name String
47 * FILE locationInformation's file name String
48 * LINE locationInformation's line number String
49 * METHOD locationInformation's method name String
50 * MSG message Object
51 * NDC NDC String
52 * EXCEPTION throwable string representation ThrowableInformation
53 * TIMESTAMP timestamp Long
54 * THREAD thread String
55 * PROP.keyName entry in the Property hashtable String
56 * mapped to the key [keyName]
57
58 * NOTE: the values for the 'keyName' portion of the MDC and PROP mappings must
59 * be an exact match to the key in the hashTable (case sensitive).
60 *
61 * If the passed-in field is null or doesn't match an entry
62 * in the above-described mapping, an exception is thrown.
63 *
64 * @author Scott Deboy (sdeboy@apache.org)
65 * @author Paul Smith (psmith@apache.org)
66 *
67 */
68 public final class LoggingEventFieldResolver {
69 /***
70 * Keyword list.
71 */
72 public static final List KEYWORD_LIST = new ArrayList();
73 /***
74 * LOGGER string literal.
75 */
76 public static final String LOGGER_FIELD = "LOGGER";
77 /***
78 * LEVEL string literal.
79 */
80 public static final String LEVEL_FIELD = "LEVEL";
81 /***
82 * CLASS string literal.
83 */
84 public static final String CLASS_FIELD = "CLASS";
85 /***
86 * FILE string literal.
87 */
88 public static final String FILE_FIELD = "FILE";
89 /***
90 * LINE string literal.
91 */
92 public static final String LINE_FIELD = "LINE";
93 /***
94 * METHOD string literal.
95 */
96 public static final String METHOD_FIELD = "METHOD";
97 /***
98 * MSG string literal.
99 */
100 public static final String MSG_FIELD = "MSG";
101 /***
102 * NDC string literal.
103 */
104 public static final String NDC_FIELD = "NDC";
105 /***
106 * EXCEPTION string literal.
107 */
108 public static final String EXCEPTION_FIELD = "EXCEPTION";
109 /***
110 * TIMESTAMP string literal.
111 */
112 public static final String TIMESTAMP_FIELD = "TIMESTAMP";
113 /***
114 * THREAD string literal.
115 */
116 public static final String THREAD_FIELD = "THREAD";
117 /***
118 * PROP. string literal.
119 */
120 public static final String PROP_FIELD = "PROP.";
121 /***
122 * empty string literal.
123 */
124 public static final String EMPTY_STRING = "";
125 /***
126 * LOGGER string literal.
127 */
128 private static final LoggingEventFieldResolver RESOLVER =
129 new LoggingEventFieldResolver();
130
131 /***
132 * Create new instance.
133 */
134 private LoggingEventFieldResolver() {
135 super();
136 KEYWORD_LIST.add(LOGGER_FIELD);
137 KEYWORD_LIST.add(LEVEL_FIELD);
138 KEYWORD_LIST.add(CLASS_FIELD);
139 KEYWORD_LIST.add(FILE_FIELD);
140 KEYWORD_LIST.add(LINE_FIELD);
141 KEYWORD_LIST.add(METHOD_FIELD);
142 KEYWORD_LIST.add(MSG_FIELD);
143 KEYWORD_LIST.add(NDC_FIELD);
144 KEYWORD_LIST.add(EXCEPTION_FIELD);
145 KEYWORD_LIST.add(TIMESTAMP_FIELD);
146 KEYWORD_LIST.add(THREAD_FIELD);
147 KEYWORD_LIST.add(PROP_FIELD);
148 }
149
150 /***
151 * Apply fields.
152 * @param replaceText replacement text.
153 * @param event logging event.
154 * @return evaluted expression
155 */
156 public String applyFields(final String replaceText,
157 final LoggingEvent event) {
158 if (replaceText == null) {
159 return null;
160 }
161 InFixToPostFix.CustomTokenizer tokenizer = new InFixToPostFix.CustomTokenizer(replaceText);
162 StringBuffer result = new StringBuffer();
163 boolean found = false;
164
165 while (tokenizer.hasMoreTokens()) {
166 String token = tokenizer.nextToken();
167 if (isField(token) || token.toUpperCase(Locale.US).startsWith(PROP_FIELD)) {
168 result.append(getValue(token, event).toString());
169 found = true;
170 } else {
171 result.append(token);
172 }
173 }
174 if (found) {
175 return result.toString();
176 }
177 return null;
178 }
179
180 /***
181 * Get singleton instance.
182 * @return singleton instance
183 */
184 public static LoggingEventFieldResolver getInstance() {
185 return RESOLVER;
186 }
187
188 /***
189 * Determines if specified string is a recognized field.
190 * @param fieldName field name
191 * @return true if recognized field.
192 */
193 public boolean isField(final String fieldName) {
194 if (fieldName != null) {
195 return (KEYWORD_LIST.contains(
196 fieldName.toUpperCase(Locale.US))
197 || fieldName.toUpperCase().startsWith(PROP_FIELD));
198 }
199 return false;
200 }
201
202 /***
203 * Get value of field.
204 * @param fieldName field
205 * @param event event
206 * @return value of field
207 */
208 public Object getValue(final String fieldName,
209 final LoggingEvent event) {
210 String upperField = fieldName.toUpperCase(Locale.US);
211 if (LOGGER_FIELD.equals(upperField)) {
212 return event.getLoggerName();
213 } else if (LEVEL_FIELD.equals(upperField)) {
214 return event.getLevel();
215 } else if (MSG_FIELD.equals(upperField)) {
216 return event.getMessage();
217 } else if (NDC_FIELD.equals(upperField)) {
218 String ndcValue = event.getNDC();
219 return ((ndcValue == null) ? EMPTY_STRING : ndcValue);
220 } else if (EXCEPTION_FIELD.equals(upperField)) {
221 String[] throwableRep = event.getThrowableStrRep();
222 if (throwableRep == null) {
223 return EMPTY_STRING;
224 } else {
225 return getExceptionMessage(throwableRep);
226 }
227 } else if (TIMESTAMP_FIELD.equals(upperField)) {
228 return new Long(event.timeStamp);
229 } else if (THREAD_FIELD.equals(upperField)) {
230 return event.getThreadName();
231 } else if (upperField.startsWith(PROP_FIELD)) {
232
233 Object propValue = event.getMDC(fieldName.substring(5));
234 if (propValue == null) {
235
236 String lowerPropKey = fieldName.substring(5).toLowerCase();
237 Set entrySet = event.getProperties().entrySet();
238 for (Iterator iter = entrySet.iterator();iter.hasNext();) {
239 Map.Entry thisEntry = (Map.Entry) iter.next();
240 if (thisEntry.getKey().toString().toLowerCase().equals(lowerPropKey)) {
241 propValue = thisEntry.getValue();
242 }
243 }
244 }
245 return ((propValue == null) ? EMPTY_STRING : propValue.toString());
246 } else {
247 LocationInfo info = event.getLocationInformation();
248 if (CLASS_FIELD.equals(upperField)) {
249 return ((info == null) ? EMPTY_STRING : info.getClassName());
250 } else if (FILE_FIELD.equals(upperField)) {
251 return ((info == null) ? EMPTY_STRING : info.getFileName());
252 } else if (LINE_FIELD.equals(upperField)) {
253 return ((info == null) ? EMPTY_STRING : info.getLineNumber());
254 } else if (METHOD_FIELD.equals(upperField)) {
255 return ((info == null) ? EMPTY_STRING : info.getMethodName());
256 }
257 }
258
259
260 throw new IllegalArgumentException("Unsupported field name: " + fieldName);
261 }
262
263 /***
264 * Get message from throwable representation.
265 * @param exception exception
266 * @return message
267 */
268 private static String getExceptionMessage(final String[] exception) {
269 StringBuffer buff = new StringBuffer();
270 for (int i = 0; i < exception.length; i++) {
271 buff.append(exception[i]);
272 }
273 return buff.toString();
274 }
275 }