1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* ident "%Z%%M% %I% %E% SMI" */ 28 29 package com.sun.solaris.service.logging; 30 31 import java.text.*; 32 import java.util.*; 33 import java.util.logging.Formatter; 34 import java.util.logging.Handler; 35 import java.util.logging.LogRecord; 36 37 import com.sun.solaris.service.exception.SuccinctStackTraceFormatter; 38 39 /** 40 * This handler outputs LogRecords with <code>syslog(3C)</code> to the 41 * given facility with a severity translated by Level with a fixed 42 * table. Formatters are not used. 43 * 44 * Multiple SyslogHandlers may not be in concurrent use in one virtual 45 * machine. 46 */ 47 public final class SyslogHandler extends Handler { 48 /** 49 * <code>syslog(3C)</code> ident string, prepended to every 50 * message. 51 */ 52 private String ident; 53 54 /** 55 * <code>syslog</code> facility to be logged to. 56 */ 57 private Facility facility; 58 59 /** 60 * Records the instance of this singleton. 61 */ 62 private static SyslogHandler instance = null; 63 64 /** 65 * Flag whether stack traces should be output when a record's 66 * <code>thrown</code> field is set. They will be formatted in 67 * a single line by <code>SuccinctStackTraceFormatter</code>, 68 * which does not include the Throwable's description, since 69 * it's presumably described by the log message). Default 70 * <code>true</code>. 71 */ 72 private static boolean useStackTraces = true; 73 74 /** 75 * Default logging option value. Sets no options. (Corresponds 76 * to the <code>logopt</code> argument to openlog(3c).) 77 */ 78 private static final int DEF_LOGOPT = 0; 79 80 /** 81 * Flag to set whether log records should indicate the record's 82 * logger. (default false) 83 */ 84 private boolean useLoggerName = false; 85 86 /** 87 * Flag to set whether log records should indicate the last 88 * component of the record's logger name, if useLoggerName isn't 89 * set. (default true) 90 */ 91 private boolean useShortLoggerName = true; 92 93 static { 94 System.loadLibrary("jsyslog"); 95 } 96 SyslogHandler(String ident, Facility facility)97 private SyslogHandler(String ident, Facility facility) 98 { 99 if (ident == null || facility == null) 100 throw new IllegalArgumentException(); 101 102 this.ident = ident; 103 this.facility = facility; 104 105 openlog(ident, DEF_LOGOPT, facility.getNative()); 106 instance = this; 107 } 108 109 /** 110 * Return this virtual machine's instance of SyslogHandler, 111 * creating one which logs with the given identity to the given 112 * facility if necessary, unless an instance with a different 113 * identity or facility is already open, in which case an 114 * IllegalArgumentException is thrown. 115 * 116 * @throws IllegalArgumentException if the requested identity or 117 * facility differs from a previously-created instance. 118 */ getInstance(String ident, Facility facility)119 public static SyslogHandler getInstance(String ident, 120 Facility facility) 121 { 122 if (instance != null) { 123 if (!instance.ident.equals(ident) || 124 !instance.facility.equals(facility)) 125 throw new IllegalArgumentException(); 126 else 127 return (instance); 128 } else 129 return (instance = new SyslogHandler(ident, facility)); 130 } 131 finalize()132 public void finalize() 133 { 134 try { 135 close(); 136 } catch (Exception e) { 137 // superclass-defined exceptions do not apply 138 } 139 } 140 toString()141 public String toString() 142 { 143 return ("SyslogHandler(" + ident + ", " + facility.toString() + 144 ")"); 145 } 146 147 /** 148 * Calls <code>syslog(3C)</code>. 149 */ syslog(int severity, String message)150 private static native void syslog(int severity, String message); 151 152 /** 153 * Calls <code>openlog(3C)</code>. 154 */ openlog(String ident, int logopt, int facility)155 private static native void openlog(String ident, int logopt, 156 int facility); 157 158 /** 159 * Calls <code>closelog(3C)</code>. 160 */ closelog()161 private static native void closelog(); 162 163 /** 164 * Publishes the given record with its associated Severity (or 165 * infers its severity with Severity.severityForLevel(), if 166 * another type of Level is used), if the result is non-null. 167 */ publish(LogRecord record)168 public void publish(LogRecord record) 169 { 170 Severity severity; 171 172 if (record.getLevel() instanceof Severity) 173 severity = (Severity)record.getLevel(); 174 else 175 severity = Severity.severityForLevel(record 176 .getLevel()); 177 178 if (getLevel().intValue() > severity.intValue()) 179 return; 180 181 /* 182 * If the severity is null, the message isn't meant to 183 * be sent to syslog. 184 */ 185 if (severity == null) 186 return; 187 188 StringBuffer message = new StringBuffer(); 189 String loggerName = record.getLoggerName(); 190 if (useLoggerName) { 191 if (loggerName != null) { 192 message.append("("); 193 message.append(record.getLoggerName()); 194 message.append(") "); 195 } 196 } else if (useShortLoggerName) { 197 if (loggerName != null) { 198 message.append("("); 199 int lastDot = loggerName.lastIndexOf('.'); 200 if (lastDot >= 0) 201 loggerName = loggerName.substring( 202 lastDot + 1); 203 message.append(loggerName); 204 message.append(") "); 205 } 206 } 207 208 message.append(record.getMessage()); 209 210 /* 211 * If the Severity is null, it's not meant to be logged 212 * via syslog. 213 */ 214 if (record.getThrown() != null && useStackTraces == true) { 215 /* 216 * Format the stack trace as one line and tack 217 * it onto the message. 218 */ 219 message.append(" "); 220 message.append(SuccinctStackTraceFormatter 221 .formatWithDescription(record.getThrown(), 222 "with tracing information: ").toString()); 223 } 224 syslog(severity.getNative(), message.toString()); 225 } 226 flush()227 public void flush() 228 { 229 } 230 close()231 public void close() throws SecurityException 232 { 233 if (instance != null) { 234 closelog(); 235 instance = null; 236 } 237 } 238 239 /** 240 * Formatters may not be used with SyslogHandler. 241 * 242 * @throws IllegalArgumentException if the use of one is 243 * attempted. 244 */ setFormatter(Formatter formatter)245 public void setFormatter(Formatter formatter) 246 { 247 throw new IllegalArgumentException(); 248 } 249 250 /** 251 * Returns the <code>syslog(3C)</code> ident string, which is 252 * prepended to every message. 253 */ getIdent()254 public String getIdent() 255 { 256 return (ident); 257 } 258 259 /** 260 * Returns the <code>syslog</code> facility to be logged to. 261 */ getFacility()262 public Facility getFacility() 263 { 264 return (facility); 265 } 266 267 } 268