17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7f184c34Ssl  * Common Development and Distribution License (the "License").
6*7f184c34Ssl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*7f184c34Ssl  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /* ident	"%Z%%M%	%I%	%E% SMI" */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate package com.sun.solaris.service.logging;
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate import java.io.PrintWriter;
317c478bd9Sstevel@tonic-gate import java.io.StringWriter;
327c478bd9Sstevel@tonic-gate import java.text.*;
337c478bd9Sstevel@tonic-gate import java.util.*;
347c478bd9Sstevel@tonic-gate import java.util.logging.Formatter;
357c478bd9Sstevel@tonic-gate import java.util.logging.LogRecord;
36*7f184c34Ssl import java.security.PrivilegedAction;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate import com.sun.solaris.service.exception.SuccinctStackTraceFormatter;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /**
417c478bd9Sstevel@tonic-gate  * Formats a LogRecord in a human-readable, <code>syslog</code>-like
427c478bd9Sstevel@tonic-gate  * format, and is intended for use with non-syslog handlers, such as
437c478bd9Sstevel@tonic-gate  * FileHandler.
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * Multi-line messages are automatically indented by four spaces to make
467c478bd9Sstevel@tonic-gate  * subsequent lines easier to differentiate from new records.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate public class SysloglikeFormatter extends Formatter {
497c478bd9Sstevel@tonic-gate 	/**
507c478bd9Sstevel@tonic-gate 	 * The date set for each published Record.
517c478bd9Sstevel@tonic-gate 	 */
527c478bd9Sstevel@tonic-gate 	private Date date = new Date();
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 	/**
557c478bd9Sstevel@tonic-gate 	 * Format string for published dates.
567c478bd9Sstevel@tonic-gate 	 */
577c478bd9Sstevel@tonic-gate 	private final static String dateFormat =
587c478bd9Sstevel@tonic-gate 	    "MMM d kk:mm:ss";
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	/**
617c478bd9Sstevel@tonic-gate 	 * For published dates, the formatter.
627c478bd9Sstevel@tonic-gate 	 */
637c478bd9Sstevel@tonic-gate 	private DateFormat dateFormatter;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	/**
667c478bd9Sstevel@tonic-gate 	 * For published dates, the argument to date formatter.
677c478bd9Sstevel@tonic-gate 	 */
687c478bd9Sstevel@tonic-gate 	private Object args[] = { date };
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	/**
717c478bd9Sstevel@tonic-gate 	 * Line separator string.
727c478bd9Sstevel@tonic-gate 	 */
737c478bd9Sstevel@tonic-gate 	private String lineSeparator = (String)java.security.AccessController
74*7f184c34Ssl 	    .doPrivileged(new PrivilegedAction() {
75*7f184c34Ssl 		public Object run() {
76*7f184c34Ssl 			return System.getProperty("line.separator");
77*7f184c34Ssl 		}
78*7f184c34Ssl 	});
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	/**
817c478bd9Sstevel@tonic-gate 	 * Flag to set whether log records should indicate the name of
827c478bd9Sstevel@tonic-gate 	 * the class generating the record, if possible.  (default
837c478bd9Sstevel@tonic-gate 	 * false)
847c478bd9Sstevel@tonic-gate 	 */
857c478bd9Sstevel@tonic-gate 	private boolean useClassName = false;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	/**
887c478bd9Sstevel@tonic-gate 	 * Flag to set whether log records should indicate the record's
897c478bd9Sstevel@tonic-gate 	 * logger, if useClassName isn't set and the class name was
907c478bd9Sstevel@tonic-gate 	 * available.  (default false)
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	private boolean useLoggerName = false;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/**
957c478bd9Sstevel@tonic-gate 	 * Flag to set whether log records should indicate the last
967c478bd9Sstevel@tonic-gate 	 * component of the record's logger name, if useLoggerName isn't
977c478bd9Sstevel@tonic-gate 	 * set.  (default true)
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	private boolean useShortLoggerName = true;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/**
1027c478bd9Sstevel@tonic-gate 	 * Flag to set whether log records should indicate the method
1037c478bd9Sstevel@tonic-gate 	 * used to invoke the logger, if available.  (default false)
1047c478bd9Sstevel@tonic-gate 	 */
1057c478bd9Sstevel@tonic-gate 	private boolean useMethodName = false;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/**
1087c478bd9Sstevel@tonic-gate 	 * Flag to set whether each record should be split into two
1097c478bd9Sstevel@tonic-gate 	 * lines such that the severity and message are on a line by
1107c478bd9Sstevel@tonic-gate 	 * themselves.  (default false)
1117c478bd9Sstevel@tonic-gate 	 */
1127c478bd9Sstevel@tonic-gate 	private boolean useTwoLineStyle = false;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	/**
1157c478bd9Sstevel@tonic-gate 	 * Format the given LogRecord.
1167c478bd9Sstevel@tonic-gate 	 * @param record the log record to be formatted.
1177c478bd9Sstevel@tonic-gate 	 * @return a formatted log record.
1187c478bd9Sstevel@tonic-gate 	 */
format(LogRecord record)1197c478bd9Sstevel@tonic-gate 	public synchronized String format(LogRecord record)
1207c478bd9Sstevel@tonic-gate 	{
1217c478bd9Sstevel@tonic-gate 		StringBuffer sb = new StringBuffer();
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		date.setTime(record.getMillis());
1247c478bd9Sstevel@tonic-gate 		StringBuffer text = new StringBuffer();
1257c478bd9Sstevel@tonic-gate 		if (dateFormatter == null)
1267c478bd9Sstevel@tonic-gate 			dateFormatter = new SimpleDateFormat(dateFormat);
1277c478bd9Sstevel@tonic-gate 		sb.append(dateFormatter.format(date));
1287c478bd9Sstevel@tonic-gate 
129*7f184c34Ssl 		if (record.getSourceClassName() != null && useClassName) {
1307c478bd9Sstevel@tonic-gate 			sb.append(" ");
1317c478bd9Sstevel@tonic-gate 			sb.append(record.getSourceClassName());
1327c478bd9Sstevel@tonic-gate 		} else if (useLoggerName) {
1337c478bd9Sstevel@tonic-gate 			if (record.getLoggerName() != null) {
1347c478bd9Sstevel@tonic-gate 				sb.append(" ");
1357c478bd9Sstevel@tonic-gate 				sb.append(record.getLoggerName());
1367c478bd9Sstevel@tonic-gate 			}
1377c478bd9Sstevel@tonic-gate 		} else if (useShortLoggerName) {
1387c478bd9Sstevel@tonic-gate 			String loggerName = record.getLoggerName();
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 			if (loggerName != null) {
1417c478bd9Sstevel@tonic-gate 				sb.append(" ");
1427c478bd9Sstevel@tonic-gate 				int lastDot = loggerName.lastIndexOf('.');
1437c478bd9Sstevel@tonic-gate 				if (lastDot >= 0)
1447c478bd9Sstevel@tonic-gate 					loggerName = loggerName.substring(
1457c478bd9Sstevel@tonic-gate 					    lastDot + 1);
1467c478bd9Sstevel@tonic-gate 				sb.append(loggerName);
1477c478bd9Sstevel@tonic-gate 			}
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 
150*7f184c34Ssl 		if (record.getSourceMethodName() != null && useMethodName) {
1517c478bd9Sstevel@tonic-gate 			sb.append(" ");
1527c478bd9Sstevel@tonic-gate 			sb.append(record.getSourceMethodName());
1537c478bd9Sstevel@tonic-gate 		}
1547c478bd9Sstevel@tonic-gate 		if (useTwoLineStyle)
1557c478bd9Sstevel@tonic-gate 			sb.append(lineSeparator);
1567c478bd9Sstevel@tonic-gate 		else
1577c478bd9Sstevel@tonic-gate 			sb.append(" ");
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 		String message = formatMessage(record);
1607c478bd9Sstevel@tonic-gate 		message = message.replaceAll("\n", lineSeparator + "    ");
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		sb.append(record.getLevel()).toString();
1637c478bd9Sstevel@tonic-gate 		sb.append(": ");
1647c478bd9Sstevel@tonic-gate 		sb.append(message);
1657c478bd9Sstevel@tonic-gate 		if (record.getThrown() != null) {
1667c478bd9Sstevel@tonic-gate 			sb.append(" ");
1677c478bd9Sstevel@tonic-gate 			sb.append(SuccinctStackTraceFormatter
1687c478bd9Sstevel@tonic-gate 			    .formatWithDescription(record.getThrown(),
1697c478bd9Sstevel@tonic-gate 			    "with tracing information: ").toString());
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 		sb.append(lineSeparator);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		return sb.toString();
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate }
176