I don't know if the previous email, and this one, is the correct way for non-Contributors to submit changes. I saw no responses to the previous email, so if I'm doing things incorrectly, please let me know the correct proceedure.
I found two problems with my previous submission: 1. It broke the LogFactor5 (lf5) contributions. 2. It introduced a bug that I didn't notice when I was testing (I need to set up JUnit, and create test cases). Attached are updated versions of all the files, and diff files that identify the changes. The changes from log4j original source are as follows: o.a.l.helpers.AbsoluteTimeDateFormat 1. Modified to use Locale-specific decimal separator between seconds and milliseconds 2. Added protected method getFormatString() which returns either "HH:mm:ss,SSS" or "HH:mm:ss.SSS" depending on the Locale-specific decimal separator. o.a.l.helpers.DateTimeDateFormat 1. Modified format(Date, StringBuffer, FieldPosition) to get the date portion of the date-time string at most once per day (rather than for each call to the method.). 2. Modified parse(String, ParsePosition) to actually parse a date string. This parse method is not lenient; i.e., the String must be in "dd MMM yyyy HH:mm:ssdSSS" format (where 'd' is the Locale-specific decimal seprator). o.a.l.helpers.ISO8601DateFormat 1. Modified format(Date, StringBuffer, FieldPosition) to get the date portion of the date-time string at most once per day (rather than for each call to the method.). 2. Modified format(Date, StringBuffer, FieldPosition) to get the time portion of the date-time string from the super-class AbsoluteTimeDateFormat rather than repeating the code of the super-class. 3. Modified parse(String, ParsePosition) to actually parse a date string. This parse method is not lenient; i.e., the String must be in "yyyy-MM-dd HH:mm:ssdSSS" format (where 'd' is the Locale-specific decimal seprator). o.a.l.lf5.util.LogFileParser 1. Modified parseDate(String) to use the updated ISO8601DateFormat.parse method to turn the logged String into a Date object. o.a.l.lf5.viewer.FilteredLogTableModel 1. Modified getColumn(int, LogRecord) to display the date and time String using DateTimeDateFormat.format rather than Date.toString() + the long timestamp. I hope these changes are acceptable, and if there is some other way that I should be submitting such changes then I hope I will be set on the correct path. Mike McAngus Associate Chief Engineer Wendy's International Knowledge Management 614-764-6776 [EMAIL PROTECTED] wrote: >The output of AbsoluteTimeDateFormat always uses a comma (",") as the >decimal separator for fractional seconds. >In many countries, the period (".") is used as the decimal separator. > >[rest deleted] >
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.txt file. */ package org.apache.log4j.helpers; import java.util.Date; import java.util.Calendar; import java.util.TimeZone; import java.util.Locale; import java.text.FieldPosition; import java.text.ParsePosition; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; /** Formats a {@link Date} in the format "HH:mm:ssdSSS", where the decimal separator, 'd', is locale specific.<br> For example, "15:49:37,459" for most European and East European countries, or "15:49:37.459" for most of the Americas, most of the Middle East and most of East Asia. @author Ceki Gülcü @author Andrew Vajoczki @author Mike McAngus @since 0.7.5 */ public class AbsoluteTimeDateFormat extends DateFormat { /** String constant used to specify {@link org.apache.log4j.helpers.AbsoluteTimeDateFormat} in layouts. Current value is <b>ABSOLUTE</b>. */ public final static String ABS_TIME_DATE_FORMAT = "ABSOLUTE"; /** String constant used to specify {@link org.apache.log4j.helpers.DateTimeDateFormat} in layouts. Current value is <b>DATE</b>. */ public final static String DATE_AND_TIME_DATE_FORMAT = "DATE"; /** String constant used to specify {@link org.apache.log4j.helpers.ISO8601DateFormat} in layouts. Current value is <b>ISO8601</b>. */ public final static String ISO8601_DATE_FORMAT = "ISO8601"; /* formatString specifies the String that would have been used if SimpleDateFormat were used to format the time instead of this class. The decimal separator, and millisecond specification for the time will be added when this class is instantiated. */ private String formatString = "HH:mm:ss"; /* Set default decimal separator. One or the other has to be chosen, so for historical purposes we choose the comma. */ private char decimalSeparator = ','; public AbsoluteTimeDateFormat() { this(TimeZone.getDefault(),Locale.getDefault()); } public AbsoluteTimeDateFormat(TimeZone timeZone) { this(timeZone,Locale.getDefault()); } public AbsoluteTimeDateFormat(Locale locale) { this(TimeZone.getDefault(),locale); } public AbsoluteTimeDateFormat(TimeZone timeZone, Locale locale) { setCalendar(Calendar.getInstance(timeZone, locale)); setDecimalSeparator(locale); } private static long previousTime; private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ssd" /** <p> Appends to <code>sbuf</code> the millisecond timestamp in <code>Locale</code> specific format. </p> <p> For example, "HH:mm:ss,SSS" (e.g. "15:49:37,459") for most European and East European countries, or "HH:mm:ss.SSS" (e.g. "15:49:37.459") for most of the Americas, most of the Middle East and most of East Asia. </p> @param date the date to format @param sbuf the string buffer to write to @param fieldPosition remains untouched */ public StringBuffer format(Date date, StringBuffer sbuf, FieldPosition fieldPosition) { long now = date.getTime(); int millis = (int)(now % 1000); if ((now - millis) == previousTime) { sbuf.append(previousTimeWithoutMillis); } else { // We reach this point at most once per second // across all threads instead of each time format() // is called. This saves considerable CPU time. calendar.setTime(date); int start = sbuf.length(); int hour = calendar.get(Calendar.HOUR_OF_DAY); if(hour < 10) { sbuf.append('0'); } sbuf.append(hour); sbuf.append(':'); int mins = calendar.get(Calendar.MINUTE); if(mins < 10) { sbuf.append('0'); } sbuf.append(mins); sbuf.append(':'); int secs = calendar.get(Calendar.SECOND); if(secs < 10) { sbuf.append('0'); } sbuf.append(secs); sbuf.append(decimalSeparator); // store the time string for next time to avoid recomputation sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0); previousTime = now - millis; } if(millis < 100) sbuf.append('0'); if(millis < 10) sbuf.append('0'); sbuf.append(millis); return sbuf; } /** Returns the format string that would be used by <code>SimpleDateFormat</code> if it was used to format the absolute time. <p> This method is protected because the format string is only of interest to the parse methods of subclasses. </p> @return The format <code>String</code>. */ protected String getFormatString() { return formatString; } /** Sets the decimalSeparator used for displaying Millisecond timestamps. */ private void setDecimalSeparator(Locale locale) { NumberFormat nf = NumberFormat.getInstance(locale); if (nf instanceof DecimalFormat) { decimalSeparator = ((DecimalFormat)nf).getDecimalFormatSymbols().getDecimalSeparator(); } // set the rest of the formatString formatString += decimalSeparator + "SSS"; } /** This method does not do anything but return <code>null</code>. */ public Date parse(String s, ParsePosition pos) { return null; } }
Compare: (<)ORIGINAL-1.2.3\org\apache\log4j\helpers\AbsoluteTimeDateFormat.java (3532 bytes) with: (>)MODIFIED-1.2.3\org\apache\log4j\helpers\AbsoluteTimeDateFormat.java (5728 bytes) 6c6,7 < * distribution in the LICENSE.txt file. */ --- > * distribution in the LICENSE.txt file. > */ 13a14 > import java.util.Locale; 16a18,19 > import java.text.DecimalFormat; > import java.text.NumberFormat; 19,20c23,27 < Formats a {@link Date} in the format "HH:mm:ss,SSS" for example, < "15:49:37,459". --- > Formats a {@link Date} in the format "HH:mm:ssdSSS", where the decimal > separator, 'd', is locale specific.<br> > For example, "15:49:37,459" for most European and East European countries, > or "15:49:37.459" for most of the Americas, most of the Middle East and > most of East Asia. 24a31 > @author Mike McAngus 32c40,41 < value is <b>ABSOLUTE</b>. */ --- > value is <b>ABSOLUTE</b>. > */ 49,51c58,74 < public < AbsoluteTimeDateFormat() { < setCalendar(Calendar.getInstance()); --- > /* > formatString specifies the String that would have been used if > SimpleDateFormat were used to format the time instead of this > class. The decimal separator, and millisecond specification > for the time will be added when this class is instantiated. > */ > private String formatString = "HH:mm:ss"; > > /* > Set default decimal separator. One or the other has to be chosen, so > for historical purposes we choose the comma. > */ > private char decimalSeparator = ','; > > public > AbsoluteTimeDateFormat() { > this(TimeZone.getDefault(),Locale.getDefault()); 56c79,90 < setCalendar(Calendar.getInstance(timeZone)); --- > this(timeZone,Locale.getDefault()); > } > > public > AbsoluteTimeDateFormat(Locale locale) { > this(TimeZone.getDefault(),locale); > } > > public > AbsoluteTimeDateFormat(TimeZone timeZone, Locale locale) { > setCalendar(Calendar.getInstance(timeZone, locale)); > setDecimalSeparator(locale); 60,64c94,105 < private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss." < < /** < Appends to <code>sbuf</code> the time in the format < "HH:mm:ss,SSS" for example, "15:49:37,459" --- > private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ssd" > > /** > <p> > Appends to <code>sbuf</code> the millisecond timestamp in <code>Locale</code> > specific format. > </p> > <p> > For example, "HH:mm:ss,SSS" (e.g. "15:49:37,459") for most European > and East European countries, or "HH:mm:ss.SSS" (e.g. "15:49:37.459") > for most of the Americas, most of the Middle East and most of East Asia. > </p> 77c118,121 < if ((now - millis) != previousTime) { --- > if ((now - millis) == previousTime) { > sbuf.append(previousTimeWithoutMillis); > } > else { 105c149 < sbuf.append(','); --- > sbuf.append(decimalSeparator); 112,116d156 < else { < sbuf.append(previousTimeWithoutMillis); < } < < 128a167,196 > Returns the format string that would be used by <code>SimpleDateFormat</code> > if it was used to format the absolute time. > <p> > This method is protected because the format string is only of interest to the > parse methods of subclasses. > </p> > > @return The format <code>String</code>. > */ > protected > String getFormatString() { > return formatString; > } > > /** > Sets the decimalSeparator used for displaying Millisecond timestamps. > */ > private > void setDecimalSeparator(Locale locale) { > NumberFormat nf = NumberFormat.getInstance(locale); > if (nf instanceof DecimalFormat) { > decimalSeparator = > ((DecimalFormat)nf).getDecimalFormatSymbols().getDecimalSeparator(); > } > > // set the rest of the formatString > formatString += decimalSeparator + "SSS"; > } > > /**
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.txt file. */ package org.apache.log4j.helpers; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import java.util.Date; import java.text.FieldPosition; import java.text.ParsePosition; import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; /** Provides a localized {@link Date} String by prepending the date formatted as "dd MMM yyyy" to the time formatted according to the description in {@link AbsoluteTimeDateFormat}. @author Ceki Gülcü @author Mike McAngus @since 0.7.5 */ public class DateTimeDateFormat extends AbsoluteTimeDateFormat { String[] shortMonths; /* If anything needs to parse a date that this class returns, then we will use a SimpleDateFormat. The parser will be instantiated only if the parse method is called for this instance. */ private SimpleDateFormat parser; public DateTimeDateFormat() { this(TimeZone.getDefault(), Locale.getDefault()); } public DateTimeDateFormat(TimeZone timeZone) { this(timeZone, Locale.getDefault()); } public DateTimeDateFormat(Locale locale) { this(TimeZone.getDefault(),locale); } public DateTimeDateFormat(TimeZone timeZone, Locale locale) { super(timeZone, locale); shortMonths = new DateFormatSymbols(locale).getShortMonths(); now = (Calendar)calendar.clone(); } private Calendar now; private int lastDate = 0; private char[] lastDateString = new char[12]; // "dd MMM yyyy " /** Appends to <code>sbuf</code> the date and time in "dd MMM yyyy HH:mm:ssdSSS" format, where "d" is the locale specific decimal separator. For example, "06 Nov 1994 15:49:37,459" for most European and East European countries, or "06 Nov 1994 15:49:37.459" for most of the Americas, most of the Middle East and most of East Asia. @param sbuf the string buffer to write to @see AbsoluteTimeDateFormat */ public StringBuffer format(Date date, StringBuffer sbuf, FieldPosition fieldPosition) { now.setTime(date); // Created comparison date in yyyyDDD format int today = (1000 * now.get(Calendar.YEAR)) + now.get(Calendar.DAY_OF_YEAR); if (today == lastDate) { sbuf.append(lastDateString); } else { // We reach this point at most once per day // across all threads instead of each time format() // is called. This saves considerable CPU time. lastDate = today; int start = sbuf.length(); int day = now.get(Calendar.DAY_OF_MONTH); if(day < 10) sbuf.append('0'); sbuf.append(day); sbuf.append(' '); sbuf.append(shortMonths[now.get(Calendar.MONTH)]); sbuf.append(' '); int year = now.get(Calendar.YEAR); sbuf.append(year); sbuf.append(' '); sbuf.getChars(start, sbuf.length(), lastDateString, 0); } // Add the time to the date string. return super.format(date, sbuf, fieldPosition); } /** Returns a <code>Date</code> for the supplied date/time (<code>text</code>) string starting at the given parse position. <p>The <code>text</code> string <strong>MUST</strong> be in "dd MMM yyyy HH:mm:ssdSSS" format, where "d" is the locale specific decimal separator.</p> @param text The date/time string to be parsed @param pos On input, the position at which to start parsing; on output, the position at which parsing terminated, or the start position if the parse failed. @return A Date, or null if <code>text</code> could not be parsed */ public Date parse(String text, ParsePosition pos) { if (parser == null) { parser = new SimpleDateFormat("dd MMM yyyy " + super.getFormatString()); parser.setLenient(false); } return parser.parse(text,pos); } }
Compare: (<)ORIGINAL-1.2.3\org\apache\log4j\helpers\DateTimeDateFormat.java (1885 bytes) with: (>)MODIFIED-1.2.3\org\apache\log4j\helpers\DateTimeDateFormat.java (4279 bytes) 6c6,7 < * distribution in the LICENSE.txt file. */ --- > * distribution in the LICENSE.txt file. > */ 11a12 > import java.util.Locale; 16,21c18,27 < < /** < Formats a {@link Date} in the format "dd MMM YYYY HH:mm:ss,SSS" for example, < "06 Nov 1994 15:49:37,459". < < @author Ceki Gülcü --- > import java.text.SimpleDateFormat; > > /** > Provides a localized {@link Date} String by prepending the date formatted > as "dd MMM yyyy" to the time formatted according to the description in > {@link AbsoluteTimeDateFormat}. > > @author Ceki Gülcü > @author Mike McAngus > 28,31c34,43 < public < DateTimeDateFormat() { < super(); < shortMonths = new DateFormatSymbols().getShortMonths(); --- > /* > If anything needs to parse a date that this class returns, then we will > use a SimpleDateFormat. The parser will be instantiated only if the > parse method is called for this instance. > */ > private SimpleDateFormat parser; > > public > DateTimeDateFormat() { > this(TimeZone.getDefault(), Locale.getDefault()); 36,73c48 < this(); < setCalendar(Calendar.getInstance(timeZone)); < } < < /** < Appends to <code>sbuf</code> the date in the format "dd MMM YYYY < HH:mm:ss,SSS" for example, "06 Nov 1994 08:49:37,459". < < @param sbuf the string buffer to write to < */ < public < StringBuffer format(Date date, StringBuffer sbuf, < FieldPosition fieldPosition) { < < calendar.setTime(date); < < int day = calendar.get(Calendar.DAY_OF_MONTH); < if(day < 10) < sbuf.append('0'); < sbuf.append(day); < sbuf.append(' '); < sbuf.append(shortMonths[calendar.get(Calendar.MONTH)]); < sbuf.append(' '); < < int year = calendar.get(Calendar.YEAR); < sbuf.append(year); < sbuf.append(' '); < < return super.format(date, sbuf, fieldPosition); < } < < /** < This method does not do anything but return <code>null</code>. < */ < public < Date parse(java.lang.String s, ParsePosition pos) { < return null; < } --- > this(timeZone, Locale.getDefault()); 74a50,144 > > public > DateTimeDateFormat(Locale locale) { > this(TimeZone.getDefault(),locale); > } > > public > DateTimeDateFormat(TimeZone timeZone, Locale locale) { > super(timeZone, locale); > shortMonths = new DateFormatSymbols(locale).getShortMonths(); > now = (Calendar)calendar.clone(); > } > > private Calendar now; > private int lastDate = 0; > private char[] lastDateString = new char[12]; // "dd MMM yyyy " > > /** > Appends to <code>sbuf</code> the date and time in > "dd MMM yyyy HH:mm:ssdSSS" format, where "d" is the > locale specific decimal separator. > For example, "06 Nov 1994 15:49:37,459" for most > European and East European countries, or > "06 Nov 1994 15:49:37.459" for most of the Americas, > most of the Middle East and most of East Asia. > > @param sbuf the string buffer to write to > @see AbsoluteTimeDateFormat > */ > public > StringBuffer format(Date date, StringBuffer sbuf, > FieldPosition fieldPosition) { > > now.setTime(date); > > // Created comparison date in yyyyDDD format > int today = (1000 * now.get(Calendar.YEAR)) + > now.get(Calendar.DAY_OF_YEAR); > > if (today == lastDate) { > sbuf.append(lastDateString); > } > else { > // We reach this point at most once per day > // across all threads instead of each time format() > // is called. This saves considerable CPU time. > > lastDate = today; > > int start = sbuf.length(); > > int day = now.get(Calendar.DAY_OF_MONTH); > if(day < 10) > sbuf.append('0'); > sbuf.append(day); > sbuf.append(' '); > sbuf.append(shortMonths[now.get(Calendar.MONTH)]); > sbuf.append(' '); > > int year = now.get(Calendar.YEAR); > sbuf.append(year); > sbuf.append(' '); > > sbuf.getChars(start, sbuf.length(), lastDateString, 0); > } > > // Add the time to the date string. > return super.format(date, sbuf, fieldPosition); > } > > /** > Returns a <code>Date</code> for the supplied date/time (<code>text</code>) >string > starting at the given parse position. > > <p>The <code>text</code> string <strong>MUST</strong> be in "dd MMM yyyy >HH:mm:ssdSSS" > format, where "d" is the locale specific decimal separator.</p> > > @param text The date/time string to be parsed > > @param pos On input, the position at which to start parsing; on > output, the position at which parsing terminated, or the > start position if the parse failed. > > @return A Date, or null if <code>text</code> could not be parsed > */ > public > Date parse(String text, ParsePosition pos) { > if (parser == null) { > parser = new SimpleDateFormat("dd MMM yyyy " + super.getFormatString()); > parser.setLenient(false); > } > > return parser.parse(text,pos); > } > }
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software License * version 1.1, a copy of which has been included with this distribution in * the LICENSE.txt file. */ package org.apache.log4j.helpers; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import java.util.Date; import java.text.FieldPosition; import java.text.ParsePosition; import java.text.SimpleDateFormat; // Contributors: Arndt Schoenewald <[EMAIL PROTECTED]> /** Provides a localized {@link Date} String by prepending the date formatted as "yyyy-MM-dd" to the absolute time formatted according to the description in {@link AbsoluteTimeDateFormat}. <p>Refer to the <a href=http://www.cl.cam.ac.uk/~mgk25/iso-time.html>summary of the International Standard Date and Time Notation</a> for more information on this format. @author Ceki Gülcü @author Andrew Vajoczki @author Mike McAngus @since 0.7.5 */ public class ISO8601DateFormat extends AbsoluteTimeDateFormat { /* If anything needs to parse a date that this class returns, then we will use a SimpleDateFormat. The parser will be instantiated only if the parse method is called for this instance. */ private SimpleDateFormat parser; private static final String[] MONTHS = {"-01-","-02-","-03-", "-04-","-05-","-06-", "-07-","-08-","-09-", "-10-","-11-","-12-"}; public ISO8601DateFormat() { this(TimeZone.getDefault(), Locale.getDefault()); } public ISO8601DateFormat(TimeZone timeZone) { this(timeZone, Locale.getDefault()); } public ISO8601DateFormat(Locale locale) { this(TimeZone.getDefault(), locale); } public ISO8601DateFormat(TimeZone timeZone, Locale locale) { super(timeZone, locale); now = (Calendar)calendar.clone(); } private static Calendar now; private static int lastDate = 0; private static char[] lastDateString = new char[11]; // "yyyy-MM-dd " /** Appends to <code>sbuf</code> the date and time in "yyyy-MM-dd HH:mm:ssdSSS" format, where "d" is the locale specific decimal separator. For example, "1994-Nov-06 15:49:37,459" for most European and East European countries, or "1994-Nov-06 15:49:37.459" for most of the Americas, most of the Middle East and most of East Asia. @param sbuf the string buffer to write to @see AbsoluteTimeDateFormat */ public StringBuffer format(Date date, StringBuffer sbuf, FieldPosition fieldPosition) { now.setTime(date); // Created comparison date in yyyyDDD format int today = (1000 * now.get(Calendar.YEAR)) + now.get(Calendar.DAY_OF_YEAR); if (today == lastDate) { sbuf.append(lastDateString); } else { // We reach this point at most once per day // across all threads instead of each time format() // is called. This saves considerable CPU time. lastDate = today; int start = sbuf.length(); int year = now.get(Calendar.YEAR); sbuf.append(year); sbuf.append(MONTHS[now.get(Calendar.MONTH)]); int day = now.get(Calendar.DAY_OF_MONTH); if(day < 10) sbuf.append('0'); sbuf.append(day); sbuf.append(' '); sbuf.getChars(start, sbuf.length(), lastDateString, 0); } // Add the time to the date string. return super.format(date, sbuf, fieldPosition); } /** Returns a <code>Date</code> for the supplied date/time (<code>text</code>) string starting at the given parse position. <p>The <code>text</code> string <strong>MUST</strong> be in "yyyy-MM-dd HH:mm:ssdSSS" format, where "d" is the locale specific decimal separator.</p> @param text The date/time string to be parsed @param pos On input, the position at which to start parsing; on output, the position at which parsing terminated, or the start position if the parse failed. @return A Date, or null if <code>text</code> could not be parsed. */ public Date parse(String text, ParsePosition pos) { if (parser == null) { parser = new SimpleDateFormat("yyyy-MM-dd " + super.getFormatString()); parser.setLenient(false); } return parser.parse(text,pos); } }
Compare: (<)ORIGINAL-1.2.3\org\apache\log4j\helpers\ISO8601DateFormat.java (3883 bytes) with: (>)MODIFIED-1.2.3\org\apache\log4j\helpers\ISO8601DateFormat.java (4693 bytes) 12a12 > import java.util.Locale; 16a17 > import java.text.SimpleDateFormat; 20,21c22,24 < Formats a {@link Date} in the format "YYYY-mm-dd HH:mm:ss,SSS" for example < "1999-11-27 15:49:37,459". --- > Provides a localized {@link Date} String by prepending the date formatted > as "yyyy-MM-dd" to the absolute time formatted according to the description > in {@link AbsoluteTimeDateFormat}. 30a33 > @author Mike McAngus 35,36c39,53 < public < ISO8601DateFormat() { --- > /* > If anything needs to parse a date that this class returns, then we will > use a SimpleDateFormat. The parser will be instantiated only if the > parse method is called for this instance. > */ > private SimpleDateFormat parser; > > private static final String[] MONTHS = {"-01-","-02-","-03-", > "-04-","-05-","-06-", > "-07-","-08-","-09-", > "-10-","-11-","-12-"}; > > public > ISO8601DateFormat() { > this(TimeZone.getDefault(), Locale.getDefault()); 41,51c58,86 < super(timeZone); < } < < static private long lastTime; < static private char[] lastTimeString = new char[20]; < < /** < Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS" < to <code>sbuf</code>. For example: "1999-11-27 15:49:37,459". < < @param sbuf the <code>StringBuffer</code> to write to --- > this(timeZone, Locale.getDefault()); > } > > public > ISO8601DateFormat(Locale locale) { > this(TimeZone.getDefault(), locale); > } > > public > ISO8601DateFormat(TimeZone timeZone, Locale locale) { > super(timeZone, locale); > now = (Calendar)calendar.clone(); > } > > private static Calendar now; > private static int lastDate = 0; > private static char[] lastDateString = new char[11]; // "yyyy-MM-dd " > > /** > Appends to <code>sbuf</code> the date and time in > "yyyy-MM-dd HH:mm:ssdSSS" format, where "d" is the > locale specific decimal separator. > For example, "1994-Nov-06 15:49:37,459" for most > European and East European countries, or > "1994-Nov-06 15:49:37.459" for most of the Americas, > most of the Middle East and most of East Asia. > > @param sbuf the string buffer to write to > @see AbsoluteTimeDateFormat 57,61c92,102 < long now = date.getTime(); < int millis = (int)(now % 1000); < < if ((now - millis) != lastTime) { < // We reach this point at most once per second --- > now.setTime(date); > > // Created comparison date in yyyyDDD format > int today = (1000 * now.get(Calendar.YEAR)) + > now.get(Calendar.DAY_OF_YEAR); > > if (today == lastDate) { > sbuf.append(lastDateString); > } > else { > // We reach this point at most once per day 65c106 < calendar.setTime(date); --- > lastDate = today; 69,90c110,115 < int year = calendar.get(Calendar.YEAR); < sbuf.append(year); < < String month; < switch(calendar.get(Calendar.MONTH)) { < case Calendar.JANUARY: month = "-01-"; break; < case Calendar.FEBRUARY: month = "-02-"; break; < case Calendar.MARCH: month = "-03-"; break; < case Calendar.APRIL: month = "-04-"; break; < case Calendar.MAY: month = "-05-"; break; < case Calendar.JUNE: month = "-06-"; break; < case Calendar.JULY: month = "-07-"; break; < case Calendar.AUGUST: month = "-08-"; break; < case Calendar.SEPTEMBER: month = "-09-"; break; < case Calendar.OCTOBER: month = "-10-"; break; < case Calendar.NOVEMBER: month = "-11-"; break; < case Calendar.DECEMBER: month = "-12-"; break; < default: month = "-NA-"; break; < } < sbuf.append(month); < < int day = calendar.get(Calendar.DAY_OF_MONTH); --- > int year = now.get(Calendar.YEAR); > sbuf.append(year); > > sbuf.append(MONTHS[now.get(Calendar.MONTH)]); > > int day = now.get(Calendar.DAY_OF_MONTH); 94,134c119,125 < < sbuf.append(' '); < < int hour = calendar.get(Calendar.HOUR_OF_DAY); < if(hour < 10) { < sbuf.append('0'); < } < sbuf.append(hour); < sbuf.append(':'); < < int mins = calendar.get(Calendar.MINUTE); < if(mins < 10) { < sbuf.append('0'); < } < sbuf.append(mins); < sbuf.append(':'); < < int secs = calendar.get(Calendar.SECOND); < if(secs < 10) { < sbuf.append('0'); < } < sbuf.append(secs); < < sbuf.append(','); < < // store the time string for next time to avoid recomputation < sbuf.getChars(start, sbuf.length(), lastTimeString, 0); < lastTime = now - millis; < } < else { < sbuf.append(lastTimeString); < } < < < if (millis < 100) < sbuf.append('0'); < if (millis < 10) < sbuf.append('0'); < < sbuf.append(millis); < return sbuf; --- > sbuf.append(' '); > > sbuf.getChars(start, sbuf.length(), lastDateString, 0); > } > > // Add the time to the date string. > return super.format(date, sbuf, fieldPosition); 138,144c129,130 < This method does not do anything but return <code>null</code>. < */ < public < Date parse(java.lang.String s, ParsePosition pos) { < return null; < } < } --- > Returns a <code>Date</code> for the supplied date/time (<code>text</code>) >string > starting at the given parse position. 145a132,152 > <p>The <code>text</code> string <strong>MUST</strong> be in "yyyy-MM-dd >HH:mm:ssdSSS" > format, where "d" is the locale specific decimal separator.</p> > > @param text The date/time string to be parsed > > @param pos On input, the position at which to start parsing; on > output, the position at which parsing terminated, or the > start position if the parse failed. > > @return A Date, or null if <code>text</code> could not be parsed. > */ > public > Date parse(String text, ParsePosition pos) { > if (parser == null) { > parser = new SimpleDateFormat("yyyy-MM-dd " + super.getFormatString()); > parser.setLenient(false); > } > > return parser.parse(text,pos); > } > }
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.txt file. */ package org.apache.log4j.lf5.util; import org.apache.log4j.lf5.Log4JLogRecord; import org.apache.log4j.lf5.LogLevel; import org.apache.log4j.lf5.LogLevelFormatException; import org.apache.log4j.lf5.LogRecord; import org.apache.log4j.lf5.viewer.LogBrokerMonitor; import org.apache.log4j.lf5.viewer.LogFactor5ErrorDialog; import org.apache.log4j.lf5.viewer.LogFactor5LoadingDialog; import org.apache.log4j.helpers.ISO8601DateFormat; import javax.swing.*; import java.io.*; import java.text.ParseException; import java.text.DateFormat; import java.util.Date; /** * Provides utility methods for input and output streams. * * @author Brad Marlborough * @author Richard Hurst * @author Mike McAngus */ // Contributed by ThoughtWorks Inc. public class LogFileParser implements Runnable { //-------------------------------------------------------------------------- // Constants: //-------------------------------------------------------------------------- public static final String RECORD_DELIMITER = "[slf5s.start]"; public static final String ATTRIBUTE_DELIMITER = "[slf5s."; public static final String DATE_DELIMITER = ATTRIBUTE_DELIMITER + "DATE]"; public static final String THREAD_DELIMITER = ATTRIBUTE_DELIMITER + "THREAD]"; public static final String CATEGORY_DELIMITER = ATTRIBUTE_DELIMITER + "CATEGORY]"; public static final String LOCATION_DELIMITER = ATTRIBUTE_DELIMITER + "LOCATION]"; public static final String MESSAGE_DELIMITER = ATTRIBUTE_DELIMITER + "MESSAGE]"; public static final String PRIORITY_DELIMITER = ATTRIBUTE_DELIMITER + "PRIORITY]"; public static final String NDC_DELIMITER = ATTRIBUTE_DELIMITER + "NDC]"; //-------------------------------------------------------------------------- // Protected Variables: //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // Private Variables: //-------------------------------------------------------------------------- private static DateFormat _dateFormat = new ISO8601DateFormat(); private LogBrokerMonitor _monitor; LogFactor5LoadingDialog _loadDialog; private InputStream _in = null; //-------------------------------------------------------------------------- // Constructors: //-------------------------------------------------------------------------- public LogFileParser(File file) throws IOException, FileNotFoundException { this(new FileInputStream(file)); } public LogFileParser(InputStream stream) throws IOException { _in = stream; } //-------------------------------------------------------------------------- // Public Methods: //-------------------------------------------------------------------------- /** * Starts a new thread to parse the log file and create a LogRecord. * See run(). * @param LogBrokerMonitor */ public void parse(LogBrokerMonitor monitor) throws RuntimeException { _monitor = monitor; Thread t = new Thread(this); t.start(); } /** * Parses the file and creates new log records and adds the record * to the monitor. */ public void run() { int index = 0; int counter = 0; LogRecord temp; boolean isLogFile = false; _loadDialog = new LogFactor5LoadingDialog( _monitor.getBaseFrame(), "Loading file..."); try { String logRecords = loadLogFile(_in); while ((counter = logRecords.indexOf(RECORD_DELIMITER, index)) != -1) { temp = createLogRecord(logRecords.substring(index, counter)); isLogFile = true; if (temp != null) { _monitor.addMessage(temp); } index = counter + RECORD_DELIMITER.length(); } if (index < logRecords.length() && isLogFile) { temp = createLogRecord(logRecords.substring(index)); if (temp != null) { _monitor.addMessage(temp); } } if (isLogFile == false) { throw new RuntimeException("Invalid log file format"); } SwingUtilities.invokeLater(new Runnable() { public void run() { destroyDialog(); } }); } catch (RuntimeException e) { destroyDialog(); displayError("Error - Invalid log file format.\nPlease see documentation" + " on how to load log files."); } catch (IOException e) { destroyDialog(); displayError("Error - Unable to load log file!"); } _in = null; } //-------------------------------------------------------------------------- // Protected Methods: //-------------------------------------------------------------------------- protected void displayError(String message) { LogFactor5ErrorDialog error = new LogFactor5ErrorDialog( _monitor.getBaseFrame(), message); } //-------------------------------------------------------------------------- // Private Methods: //-------------------------------------------------------------------------- private void destroyDialog() { _loadDialog.hide(); _loadDialog.dispose(); } /** * Loads a log file from a web server into the LogFactor5 GUI. */ private String loadLogFile(InputStream stream) throws IOException { BufferedInputStream br = new BufferedInputStream(stream); int count = 0; int size = br.available(); StringBuffer sb = null; if (size > 0) { sb = new StringBuffer(size); } else { sb = new StringBuffer(1024); } while ((count = br.read()) != -1) { sb.append((char) count); } br.close(); br = null; return sb.toString(); } private String parseAttribute(String name, String record) { int index = record.indexOf(name); if (index == -1) { return null; } return getAttribute(index, record); } private long parseDate(String record) { String s = parseAttribute(DATE_DELIMITER, record); if (s == null) { return 0; } try { Date d = _dateFormat.parse(s); return d.getTime(); } catch (ParseException e) { return 0; } } private LogLevel parsePriority(String record) { String temp = parseAttribute(PRIORITY_DELIMITER, record); if (temp != null) { try { return LogLevel.valueOf(temp); } catch (LogLevelFormatException e) { return LogLevel.DEBUG; } } return LogLevel.DEBUG; } private String parseThread(String record) { return parseAttribute(THREAD_DELIMITER, record); } private String parseCategory(String record) { return parseAttribute(CATEGORY_DELIMITER, record); } private String parseLocation(String record) { return parseAttribute(LOCATION_DELIMITER, record); } private String parseMessage(String record) { return parseAttribute(MESSAGE_DELIMITER, record); } private String parseNDC(String record) { return parseAttribute(NDC_DELIMITER, record); } private String parseThrowable(String record) { return getAttribute(record.length(), record); } private LogRecord createLogRecord(String record) { if (record == null || record.trim().length() == 0) { return null; } LogRecord lr = new Log4JLogRecord(); lr.setMillis(parseDate(record)); lr.setLevel(parsePriority(record)); lr.setCategory(parseCategory(record)); lr.setLocation(parseLocation(record)); lr.setThreadDescription(parseThread(record)); lr.setNDC(parseNDC(record)); lr.setMessage(parseMessage(record)); lr.setThrownStackTrace(parseThrowable(record)); return lr; } private String getAttribute(int index, String record) { int start = record.lastIndexOf(ATTRIBUTE_DELIMITER, index - 1); if (start == -1) { return record.substring(0, index); } start = record.indexOf("]", start); return record.substring(start + 1, index).trim(); } //-------------------------------------------------------------------------- // Nested Top-Level Classes or Interfaces //-------------------------------------------------------------------------- }
Compare: (<)ORIGINAL-1.2.3\org\apache\log4j\lf5\util\LogFileParser.java (8604 bytes) with: (>)MODIFIED-1.2.3\org\apache\log4j\lf5\util\LogFileParser.java (8656 bytes) 18a18,19 > import org.apache.log4j.helpers.ISO8601DateFormat; > 21c23 < import java.text.SimpleDateFormat; --- > import java.text.DateFormat; 29a31 > * @author Mike McAngus 54c57 < private static SimpleDateFormat _sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,S"); --- > private static DateFormat _dateFormat = new ISO8601DateFormat(); 198d201 < try { 205c207,208 < Date d = _sdf.parse(s); --- > try { > Date d = _dateFormat.parse(s);
/* * Copyright (C) The Apache Software Foundation. All rights reserved. * * This software is published under the terms of the Apache Software * License version 1.1, a copy of which has been included with this * distribution in the LICENSE.txt file. */ package org.apache.log4j.lf5.viewer; import org.apache.log4j.lf5.LogRecord; import org.apache.log4j.lf5.LogRecordFilter; import org.apache.log4j.lf5.PassingLogRecordFilter; import org.apache.log4j.helpers.DateTimeDateFormat; import javax.swing.table.AbstractTableModel; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; /** * A TableModel for LogRecords which includes filtering support. * * @author Richard Wan * @author Brent Sprecher * @author Mike McAngus */ // Contributed by ThoughtWorks Inc. public class FilteredLogTableModel extends AbstractTableModel { //-------------------------------------------------------------------------- // Constants: //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // Protected Variables: //-------------------------------------------------------------------------- protected LogRecordFilter _filter = new PassingLogRecordFilter(); protected DateFormat _dateFormat = new DateTimeDateFormat(); protected List _allRecords = new ArrayList(); protected List _filteredRecords; protected int _maxNumberOfLogRecords = 5000; protected String[] _colNames = {"Date", "Thread", "Message #", "Level", "NDC", "Category", "Message", "Location", "Thrown"}; //-------------------------------------------------------------------------- // Private Variables: //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // Constructors: //-------------------------------------------------------------------------- public FilteredLogTableModel() { super(); } //-------------------------------------------------------------------------- // Public Methods: //-------------------------------------------------------------------------- public void setLogRecordFilter(LogRecordFilter filter) { _filter = filter; } public LogRecordFilter getLogRecordFilter() { return _filter; } public String getColumnName(int i) { return _colNames[i]; } public int getColumnCount() { return _colNames.length; } public int getRowCount() { return getFilteredRecords().size(); } public int getTotalRowCount() { return _allRecords.size(); } public Object getValueAt(int row, int col) { LogRecord record = getFilteredRecord(row); return getColumn(col, record); } public void setMaxNumberOfLogRecords(int maxNumRecords) { if (maxNumRecords > 0) { _maxNumberOfLogRecords = maxNumRecords; } } public synchronized boolean addLogRecord(LogRecord record) { _allRecords.add(record); if (_filter.passes(record) == false) { return false; } getFilteredRecords().add(record); fireTableRowsInserted(getRowCount(), getRowCount()); trimRecords(); return true; } /** * Forces the LogTableModel to requery its filters to determine * which records to display. */ public synchronized void refresh() { _filteredRecords = createFilteredRecordsList(); fireTableDataChanged(); } public synchronized void fastRefresh() { _filteredRecords.remove(0); fireTableRowsDeleted(0, 0); } /** * Clears all records from the LogTableModel */ public synchronized void clear() { _allRecords.clear(); _filteredRecords.clear(); fireTableDataChanged(); } //-------------------------------------------------------------------------- // Protected Methods: //-------------------------------------------------------------------------- protected List getFilteredRecords() { if (_filteredRecords == null) { refresh(); } return _filteredRecords; } protected List createFilteredRecordsList() { List result = new ArrayList(); Iterator records = _allRecords.iterator(); LogRecord current; while (records.hasNext()) { current = (LogRecord) records.next(); if (_filter.passes(current)) { result.add(current); } } return result; } protected LogRecord getFilteredRecord(int row) { List records = getFilteredRecords(); int size = records.size(); if (row < size) { return (LogRecord) records.get(row); } // a minor problem has happened. JTable has asked for // a row outside the bounds, because the size of // _filteredRecords has changed while it was looping. // return the last row. return (LogRecord) records.get(size - 1); } protected Object getColumn(int col, LogRecord lr) { if (lr == null) { return "NULL Column"; } switch (col) { case 0: return _dateFormat.format(new Date(lr.getMillis())); case 1: return lr.getThreadDescription(); case 2: return new Long(lr.getSequenceNumber()); case 3: return lr.getLevel(); case 4: return lr.getNDC(); case 5: return lr.getCategory(); case 6: return lr.getMessage(); case 7: return lr.getLocation(); case 8: return lr.getThrownStackTrace(); default: String message = "The column number " + col + "must be between 0 and 8"; throw new IllegalArgumentException(message); } } // We don't want the amount of rows to grow without bound, // leading to a out-of-memory-exception. Especially not good // in a production environment :) // This method & clearLogRecords() are synchronized so we don't // delete rows that don't exist. protected void trimRecords() { if (needsTrimming()) { trimOldestRecords(); } } protected boolean needsTrimming() { return (_allRecords.size() > _maxNumberOfLogRecords); } protected void trimOldestRecords() { synchronized (_allRecords) { int trim = numberOfRecordsToTrim(); if (trim > 1) { List oldRecords = _allRecords.subList(0, trim); oldRecords.clear(); refresh(); } else { _allRecords.remove(0); fastRefresh(); } } } //-------------------------------------------------------------------------- // Private Methods: //-------------------------------------------------------------------------- private int numberOfRecordsToTrim() { return _allRecords.size() - _maxNumberOfLogRecords; } //-------------------------------------------------------------------------- // Nested Top-Level Classes or Interfaces //-------------------------------------------------------------------------- }
Compare: (<)ORIGINAL-1.2.3\org\apache\log4j\lf5\viewer\FilteredLogTableModel.java (7370 bytes) with: (>)MODIFIED-1.2.3\org\apache\log4j\lf5\viewer\FilteredLogTableModel.java (7500 bytes) 14c14,17 < import javax.swing.table.AbstractTableModel; --- > import org.apache.log4j.helpers.DateTimeDateFormat; > > import javax.swing.table.AbstractTableModel; > import java.text.DateFormat; 26a29 > * @author Mike McAngus 41a45 > protected DateFormat _dateFormat = new DateTimeDateFormat(); 185,188c190,193 < String date = new Date(lr.getMillis()).toString(); < switch (col) { < case 0: < return date + " (" + lr.getMillis() + ")"; --- > > switch (col) { > case 0: > return _dateFormat.format(new Date(lr.getMillis()));
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>