/** * */ package net.varkhan.base.management.logging; import java.io.IOException; /** * <b>LogMapper output formatting utilities.</b> * <p/> * * @author varkhan * @date Nov 25, 2010 * @time 9:57:21 PM */ @SuppressWarnings( { "UnusedDeclaration" }) public class LogFormat { /** * Protected constructor to enforce the singleton pattern */ protected LogFormat() { } /** * Formats a log message into a buffer. * <p/> * The escapes sequences start with %, followed by an optional padding character, * zero or more digits specifying a display width, and a field specifier character. * Each escape sequence is replaced by the specified field of the message, formatted * according to the padding and width. The field specifiers are: * <li/> <b>'%'</b>: no field is displayed, instead a literal '%' character is added * <li/> <b>'c'</b>: the context name * <li/> <b>'k'</b>: the filter key * <li/> <b>'l'</b>: the severity level (for this field the default padding is '.', and the default width is 3) * <li/> <b>'s'</b>: the number of seconds in the time-stamp * <li/> <b>'u'</b>: the number of microseconds in the time-stamp * <li/> <b>'v'</b>: the floating point event weight * <li/> <b>'m'</b>: the message content (converted to a String, using {@link java.lang.Object#toString()}) * * @param out the output buffer * @param fmt the format defining how the message should be written * @param ctx a context name * @param key a filter key * @param lev a severity level * @param tms the message time-stamp (in milliseconds) * @param val the event weight * @param msg the message content * @param <T> the type of message to be formatted * * @throws IllegalArgumentException if the format string contains invalid directives * @throws IOException if appending to the buffer produced an I/O error */ public static <T> void format(Appendable out, String fmt, String ctx, String key, int lev, long tms, double val, T msg) throws IllegalArgumentException, IOException { final int n=fmt.length(); final char[] nbf=new char[11]; for(int pos=0;pos<n;pos++) { char chr=fmt.charAt(pos); if(chr!='%') { out.append(chr); continue; } if(++pos>=n) throw new IllegalArgumentException("Invalid format sequence in '"+fmt+"' at char "+pos); chr=fmt.charAt(pos); char pad='\0'; // Look for a pad char -> 'c' if(((chr<='0')||(chr>'9')) &&((chr<'a')||(chr>'z')) &&((chr<'A')||(chr>'Z')) &&(chr!='%')) { pad=chr; if(++pos>=n) throw new IllegalArgumentException("Invalid format sequence in '"+fmt+"' at char "+pos); chr=fmt.charAt(pos); } if(chr=='\0') break; // Look for display width -> 'l' int dsp=-1; if((chr>'0')&&(chr<='9')) { dsp=0; while((chr>='0')&&(chr<='9')) { dsp*=10; dsp+=chr-'0'; if(++pos>=n) throw new IllegalArgumentException("Invalid format sequence in '"+fmt+"' at char "+pos); chr=fmt.charAt(pos); } } switch(chr) { case '%': { // Literal % out.append('%'); } break; case 'c': { // Context Name value // Pad with '.' by default if(pad=='\0') pad='.'; dsp-=ctx.length(); out.append(ctx); while(dsp>0) { out.append(pad); dsp--; } } break; case 'k': { // Filter Key value // Pad with '.' by default if(pad=='\0') pad='.'; dsp-=key.length(); out.append(key); while(dsp>0) { out.append(pad); dsp--; } } break; case 'l': { // Debug Level // Pad with '0' by default if(pad=='\0') pad='0'; // Display aligned on 3 chars by default if(dsp<0) dsp=3; while(dsp>3) { out.append(pad); dsp--; } if(dsp>2) out.append((char) ('0'+lev%10)); if(dsp>1) out.append((char) ('0'+(lev/10)%10)); if(dsp>0) out.append((char) ('0'+(lev/100)%10)); } break; case 's': { // Seconds // Pad with '0' by default if(pad=='\0') pad='0'; int j=0; long u=tms/1000; while(u!=0&&j<nbf.length) { nbf[j++]=(char) (u%10+'0'); u/=10; } if(dsp<0) while(j>0) out.append(nbf[--j]); else { while(dsp>j) { out.append(pad); dsp--; } while(dsp>0) out.append(nbf[--dsp]); } } break; case 'u': { // Micro seconds // Pad with '0' by default if(pad=='\0') pad='0'; int j=0; long u=1000*(tms%1000); while(u!=0&&j<nbf.length) { nbf[j++]=(char) (u%10+'0'); u/=10; } if(dsp<0) while(j>0) out.append(nbf[--j]); else { while(dsp>j) { out.append(pad); dsp--; } while(dsp>0) out.append(nbf[--dsp]); } } break; case 'v': { // Message // Pad with ' ' by default if(pad=='\0') pad=' '; String s=Double.toString(val); dsp-=s.length(); out.append(s); while(dsp>0) { out.append(pad); dsp--; } } break; case 'm': { // Message // Pad with ' ' by default if(pad=='\0') pad=' '; String s=msg.toString(); dsp-=s.length(); out.append(s); while(dsp>0) { out.append(pad); dsp--; } } break; default: // Ignore unrecognized types } } } /** * Formats a log message into a buffer. * * @param buf the output buffer * @param fmt the format defining how the message should be written * @param ctx a context name * @param key a filter key * @param lev a severity level * @param tms the message time-stamp (in milliseconds) * @param val the event weight * @param msg the message content * @param <T> the type of message to be formatted * * @throws IllegalArgumentException if the format string contains invalid directives * @see #format(Appendable, String, String, String, int, long, double, Object) for a complete specification of the escape sequences */ public static <T> void format(StringBuilder buf, String fmt, String ctx, String key, int lev, long tms, double val, T msg) { try { format((Appendable) buf, fmt, ctx, key, lev, tms, val, msg); } catch(IOException e) { /* That exception is never thrown by StringBuilder */ } } /** * Writes a text representation of a log message into a buffer. * <p/> * This is equivalent to {@code format(buf, "<%03l>[%k:%c] %v %m", ...)}. * * @param buf the output buffer * @param ctx a context name * @param key a filter key * @param lev a severity level * @param tms the message time-stamp (in milliseconds) * @param val the event weight * @param msg the message content * @param <T> the type of message to be formatted * * @throws IllegalArgumentException if the format string contains invalid directives * @see #format(Appendable, String, String, String, int, long, double, Object) for a complete specification of the escape sequences */ public static <T> void formatAsText(StringBuilder buf, String ctx, String key, int lev, long tms, double val, T msg) { buf.append('<').append((char) ('0'+((lev/100)%10))).append((char) ('0'+((lev/10)%10))).append((char) ('0'+(lev%10))).append('>').append('[').append(key).append(':').append(ctx).append(']').append(' ').append(val).append(' ').append(msg); } /** * Writes a text representation of a log message into a buffer. * <p/> * This is equivalent to {@code format(buf, "<%03l>[%k:%c] %v %m", ...)}. * * @param buf the output buffer * @param ctx a context name * @param key a filter key * @param lev a severity level * @param tms the message time-stamp (in milliseconds) * @param val the event weight * @param msg the message content * @param <T> the type of message to be formatted * * @throws IllegalArgumentException if the format string contains invalid directives * @throws IOException if appending to the buffer produced an I/O error * @see #format(Appendable, String, String, String, int, long, double, Object) for a complete specification of the escape sequences */ public static <T> void formatAsText(Appendable buf, String ctx, String key, int lev, long tms, double val, T msg) throws IOException { buf.append('<').append((char) ('0'+((lev/100)%10))).append((char) ('0'+((lev/10)%10))).append((char) ('0'+(lev%10))).append('>').append('[').append(key).append(':').append(ctx).append(']').append(' ').append(Double.toString(val)).append(' ').append(msg.toString()); } /** * Writes an XML representation of a log message into a buffer. * <p/> * This is equivalent to {@code format(buf, "<"+elt+" ctx=\"%c\" key=\"%k\" lev=\"%03l\" val=\"%v\" "+att+">%m</"+elt+">", ...)}. * * @param buf the output buffer * @param elt the XML element name * @param att supplemental XML element attributes * @param ctx a context name * @param key a filter key * @param lev a severity level * @param tms the message time-stamp (in milliseconds) * @param val the event weight * @param msg the message content * @param <T> the type of message to be formatted * * @throws IllegalArgumentException if the format string contains invalid directives * @throws IOException if appending to the buffer produced an I/O error * @see #format(Appendable, String, String, String, int, long, double, Object) for a complete specification of the escape sequences */ public static <T> void formatAsXML(Appendable buf, String elt, String att, String ctx, String key, int lev, long tms, double val, T msg) throws IOException { buf.append('<').append(elt); buf.append(" ctx=\"").append(ctx).append('\"'); buf.append(" key=\"").append(key).append('\"'); buf.append(" lev=\"").append((char) ('0'+((lev/100)%10))).append((char) ('0'+((lev/10)%10))).append((char) ('0'+(lev%10))).append('\"'); buf.append(" val=\"").append(Double.toString(val)).append('\"'); if(att!=null) buf.append(' ').append(att); buf.append('>'); buf.append(msg.toString()); buf.append('<').append('/').append(elt).append('>'); } }