1 16 package org.apache.log4j.helpers; 17 18 import org.apache.log4j.helpers.LogLog; 19 import org.apache.log4j.helpers.OptionConverter; 20 import org.apache.log4j.helpers.AbsoluteTimeDateFormat; 21 import org.apache.log4j.Layout; 22 import org.apache.log4j.spi.LoggingEvent; 23 import org.apache.log4j.spi.LocationInfo; 24 import java.text.DateFormat ; 25 import java.text.SimpleDateFormat ; 26 import java.util.Date ; 27 28 32 45 public class PatternParser { 46 47 private static final char ESCAPE_CHAR = '%'; 48 49 private static final int LITERAL_STATE = 0; 50 private static final int CONVERTER_STATE = 1; 51 private static final int MINUS_STATE = 2; 52 private static final int DOT_STATE = 3; 53 private static final int MIN_STATE = 4; 54 private static final int MAX_STATE = 5; 55 56 static final int FULL_LOCATION_CONVERTER = 1000; 57 static final int METHOD_LOCATION_CONVERTER = 1001; 58 static final int CLASS_LOCATION_CONVERTER = 1002; 59 static final int LINE_LOCATION_CONVERTER = 1003; 60 static final int FILE_LOCATION_CONVERTER = 1004; 61 62 static final int RELATIVE_TIME_CONVERTER = 2000; 63 static final int THREAD_CONVERTER = 2001; 64 static final int LEVEL_CONVERTER = 2002; 65 static final int NDC_CONVERTER = 2003; 66 static final int MESSAGE_CONVERTER = 2004; 67 68 int state; 69 protected StringBuffer currentLiteral = new StringBuffer (32); 70 protected int patternLength; 71 protected int i; 72 PatternConverter head; 73 PatternConverter tail; 74 protected FormattingInfo formattingInfo = new FormattingInfo(); 75 protected String pattern; 76 77 public 78 PatternParser(String pattern) { 79 this.pattern = pattern; 80 patternLength = pattern.length(); 81 state = LITERAL_STATE; 82 } 83 84 private 85 void addToList(PatternConverter pc) { 86 if(head == null) { 87 head = tail = pc; 88 } else { 89 tail.next = pc; 90 tail = pc; 91 } 92 } 93 94 protected 95 String extractOption() { 96 if((i < patternLength) && (pattern.charAt(i) == '{')) { 97 int end = pattern.indexOf('}', i); 98 if (end > i) { 99 String r = pattern.substring(i + 1, end); 100 i = end+1; 101 return r; 102 } 103 } 104 return null; 105 } 106 107 108 111 protected 112 int extractPrecisionOption() { 113 String opt = extractOption(); 114 int r = 0; 115 if(opt != null) { 116 try { 117 r = Integer.parseInt(opt); 118 if(r <= 0) { 119 LogLog.error( 120 "Precision option (" + opt + ") isn't a positive integer."); 121 r = 0; 122 } 123 } 124 catch (NumberFormatException e) { 125 LogLog.error("Category option \""+opt+"\" not a decimal integer.", e); 126 } 127 } 128 return r; 129 } 130 131 public 132 PatternConverter parse() { 133 char c; 134 i = 0; 135 while(i < patternLength) { 136 c = pattern.charAt(i++); 137 switch(state) { 138 case LITERAL_STATE: 139 if(i == patternLength) { 141 currentLiteral.append(c); 142 continue; 143 } 144 if(c == ESCAPE_CHAR) { 145 switch(pattern.charAt(i)) { 147 case ESCAPE_CHAR: 148 currentLiteral.append(c); 149 i++; break; 151 case 'n': 152 currentLiteral.append(Layout.LINE_SEP); 153 i++; break; 155 default: 156 if(currentLiteral.length() != 0) { 157 addToList(new LiteralPatternConverter( 158 currentLiteral.toString())); 159 } 162 currentLiteral.setLength(0); 163 currentLiteral.append(c); state = CONVERTER_STATE; 165 formattingInfo.reset(); 166 } 167 } 168 else { 169 currentLiteral.append(c); 170 } 171 break; 172 case CONVERTER_STATE: 173 currentLiteral.append(c); 174 switch(c) { 175 case '-': 176 formattingInfo.leftAlign = true; 177 break; 178 case '.': 179 state = DOT_STATE; 180 break; 181 default: 182 if(c >= '0' && c <= '9') { 183 formattingInfo.min = c - '0'; 184 state = MIN_STATE; 185 } 186 else 187 finalizeConverter(c); 188 } break; 190 case MIN_STATE: 191 currentLiteral.append(c); 192 if(c >= '0' && c <= '9') 193 formattingInfo.min = formattingInfo.min*10 + (c - '0'); 194 else if(c == '.') 195 state = DOT_STATE; 196 else { 197 finalizeConverter(c); 198 } 199 break; 200 case DOT_STATE: 201 currentLiteral.append(c); 202 if(c >= '0' && c <= '9') { 203 formattingInfo.max = c - '0'; 204 state = MAX_STATE; 205 } 206 else { 207 LogLog.error("Error occured in position "+i 208 +".\n Was expecting digit, instead got char \""+c+"\"."); 209 state = LITERAL_STATE; 210 } 211 break; 212 case MAX_STATE: 213 currentLiteral.append(c); 214 if(c >= '0' && c <= '9') 215 formattingInfo.max = formattingInfo.max*10 + (c - '0'); 216 else { 217 finalizeConverter(c); 218 state = LITERAL_STATE; 219 } 220 break; 221 } } if(currentLiteral.length() != 0) { 224 addToList(new LiteralPatternConverter(currentLiteral.toString())); 225 } 227 return head; 228 } 229 230 protected 231 void finalizeConverter(char c) { 232 PatternConverter pc = null; 233 switch(c) { 234 case 'c': 235 pc = new CategoryPatternConverter(formattingInfo, 236 extractPrecisionOption()); 237 currentLiteral.setLength(0); 240 break; 241 case 'C': 242 pc = new ClassNamePatternConverter(formattingInfo, 243 extractPrecisionOption()); 244 currentLiteral.setLength(0); 247 break; 248 case 'd': 249 String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT; 250 DateFormat df; 251 String dOpt = extractOption(); 252 if(dOpt != null) 253 dateFormatStr = dOpt; 254 255 if(dateFormatStr.equalsIgnoreCase( 256 AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT)) 257 df = new ISO8601DateFormat(); 258 else if(dateFormatStr.equalsIgnoreCase( 259 AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT)) 260 df = new AbsoluteTimeDateFormat(); 261 else if(dateFormatStr.equalsIgnoreCase( 262 AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT)) 263 df = new DateTimeDateFormat(); 264 else { 265 try { 266 df = new SimpleDateFormat (dateFormatStr); 267 } 268 catch (IllegalArgumentException e) { 269 LogLog.error("Could not instantiate SimpleDateFormat with " + 270 dateFormatStr, e); 271 df = (DateFormat) OptionConverter.instantiateByClassName( 272 "org.apache.log4j.helpers.ISO8601DateFormat", 273 DateFormat.class, null); 274 } 275 } 276 pc = new DatePatternConverter(formattingInfo, df); 277 currentLiteral.setLength(0); 280 break; 281 case 'F': 282 pc = new LocationPatternConverter(formattingInfo, 283 FILE_LOCATION_CONVERTER); 284 currentLiteral.setLength(0); 287 break; 288 case 'l': 289 pc = new LocationPatternConverter(formattingInfo, 290 FULL_LOCATION_CONVERTER); 291 currentLiteral.setLength(0); 294 break; 295 case 'L': 296 pc = new LocationPatternConverter(formattingInfo, 297 LINE_LOCATION_CONVERTER); 298 currentLiteral.setLength(0); 301 break; 302 case 'm': 303 pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER); 304 currentLiteral.setLength(0); 307 break; 308 case 'M': 309 pc = new LocationPatternConverter(formattingInfo, 310 METHOD_LOCATION_CONVERTER); 311 currentLiteral.setLength(0); 314 break; 315 case 'p': 316 pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER); 317 currentLiteral.setLength(0); 320 break; 321 case 'r': 322 pc = new BasicPatternConverter(formattingInfo, 323 RELATIVE_TIME_CONVERTER); 324 currentLiteral.setLength(0); 327 break; 328 case 't': 329 pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER); 330 currentLiteral.setLength(0); 333 break; 334 348 case 'x': 349 pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER); 350 currentLiteral.setLength(0); 352 break; 353 case 'X': 354 String xOpt = extractOption(); 355 pc = new MDCPatternConverter(formattingInfo, xOpt); 356 currentLiteral.setLength(0); 357 break; 358 default: 359 LogLog.error("Unexpected char [" +c+"] at position "+i 360 +" in conversion patterrn."); 361 pc = new LiteralPatternConverter(currentLiteral.toString()); 362 currentLiteral.setLength(0); 363 } 364 365 addConverter(pc); 366 } 367 368 protected 369 void addConverter(PatternConverter pc) { 370 currentLiteral.setLength(0); 371 addToList(pc); 373 state = LITERAL_STATE; 375 formattingInfo.reset(); 377 } 378 379 383 private static class BasicPatternConverter extends PatternConverter { 384 int type; 385 386 BasicPatternConverter(FormattingInfo formattingInfo, int type) { 387 super(formattingInfo); 388 this.type = type; 389 } 390 391 public 392 String convert(LoggingEvent event) { 393 switch(type) { 394 case RELATIVE_TIME_CONVERTER: 395 return (Long.toString(event.timeStamp - LoggingEvent.getStartTime())); 396 case THREAD_CONVERTER: 397 return event.getThreadName(); 398 case LEVEL_CONVERTER: 399 return event.getLevel().toString(); 400 case NDC_CONVERTER: 401 return event.getNDC(); 402 case MESSAGE_CONVERTER: { 403 return event.getRenderedMessage(); 404 } 405 default: return null; 406 } 407 } 408 } 409 410 private static class LiteralPatternConverter extends PatternConverter { 411 private String literal; 412 413 LiteralPatternConverter(String value) { 414 literal = value; 415 } 416 417 public 418 final 419 void format(StringBuffer sbuf, LoggingEvent event) { 420 sbuf.append(literal); 421 } 422 423 public 424 String convert(LoggingEvent event) { 425 return literal; 426 } 427 } 428 429 private static class DatePatternConverter extends PatternConverter { 430 private DateFormat df; 431 private Date date; 432 433 DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) { 434 super(formattingInfo); 435 date = new Date (); 436 this.df = df; 437 } 438 439 public 440 String convert(LoggingEvent event) { 441 date.setTime(event.timeStamp); 442 String converted = null; 443 try { 444 converted = df.format(date); 445 } 446 catch (Exception ex) { 447 LogLog.error("Error occured while converting date.", ex); 448 } 449 return converted; 450 } 451 } 452 453 private static class MDCPatternConverter extends PatternConverter { 454 private String key; 455 456 MDCPatternConverter(FormattingInfo formattingInfo, String key) { 457 super(formattingInfo); 458 this.key = key; 459 } 460 461 public 462 String convert(LoggingEvent event) { 463 Object val = event.getMDC(key); 464 if(val == null) { 465 return null; 466 } else { 467 return val.toString(); 468 } 469 } 470 } 471 472 473 private class LocationPatternConverter extends PatternConverter { 474 int type; 475 476 LocationPatternConverter(FormattingInfo formattingInfo, int type) { 477 super(formattingInfo); 478 this.type = type; 479 } 480 481 public 482 String convert(LoggingEvent event) { 483 LocationInfo locationInfo = event.getLocationInformation(); 484 switch(type) { 485 case FULL_LOCATION_CONVERTER: 486 return locationInfo.fullInfo; 487 case METHOD_LOCATION_CONVERTER: 488 return locationInfo.getMethodName(); 489 case LINE_LOCATION_CONVERTER: 490 return locationInfo.getLineNumber(); 491 case FILE_LOCATION_CONVERTER: 492 return locationInfo.getFileName(); 493 default: return null; 494 } 495 } 496 } 497 498 private static abstract class NamedPatternConverter extends PatternConverter { 499 int precision; 500 501 NamedPatternConverter(FormattingInfo formattingInfo, int precision) { 502 super(formattingInfo); 503 this.precision = precision; 504 } 505 506 abstract 507 String getFullyQualifiedName(LoggingEvent event); 508 509 public 510 String convert(LoggingEvent event) { 511 String n = getFullyQualifiedName(event); 512 if(precision <= 0) 513 return n; 514 else { 515 int len = n.length(); 516 517 int end = len -1 ; 521 for(int i = precision; i > 0; i--) { 522 end = n.lastIndexOf('.', end-1); 523 if(end == -1) 524 return n; 525 } 526 return n.substring(end+1, len); 527 } 528 } 529 } 530 531 private class ClassNamePatternConverter extends NamedPatternConverter { 532 533 ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) { 534 super(formattingInfo, precision); 535 } 536 537 String getFullyQualifiedName(LoggingEvent event) { 538 return event.getLocationInformation().getClassName(); 539 } 540 } 541 542 private class CategoryPatternConverter extends NamedPatternConverter { 543 544 CategoryPatternConverter(FormattingInfo formattingInfo, int precision) { 545 super(formattingInfo, precision); 546 } 547 548 String getFullyQualifiedName(LoggingEvent event) { 549 return event.getLoggerName(); 550 } 551 } 552 } 553 554 | Popular Tags |