1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.util.logging; 19 20import java.io.BufferedOutputStream; 21import java.io.IOException; 22import java.net.Socket; 23 24/** 25 * A handler that writes log messages to a socket connection. 26 * <p> 27 * This handler reads the following properties from the log manager to 28 * initialize itself: 29 * <ul> 30 * <li>java.util.logging.ConsoleHandler.level specifies the logging level, 31 * defaults to {@code Level.ALL} if this property is not found or has an invalid 32 * value. 33 * <li>java.util.logging.SocketHandler.filter specifies the name of the filter 34 * class to be associated with this handler, defaults to {@code null} if this 35 * property is not found or has an invalid value. 36 * <li>java.util.logging.SocketHandler.formatter specifies the name of the 37 * formatter class to be associated with this handler, defaults to 38 * {@code java.util.logging.XMLFormatter} if this property is not found or has 39 * an invalid value. 40 * <li>java.util.logging.SocketHandler.encoding specifies the encoding this 41 * handler will use to encode log messages, defaults to {@code null} if this 42 * property is not found or has an invalid value. 43 * <li>java.util.logging.SocketHandler.host specifies the name of the host that 44 * this handler should connect to. There's no default value for this property. 45 * <li>java.util.logging.SocketHandler.encoding specifies the port number that 46 * this handler should connect to. There's no default value for this property. 47 * </ul> 48 * <p> 49 * This handler buffers the outgoing messages, but flushes each time a log 50 * record has been published. 51 * <p> 52 * This class is not thread-safe. 53 */ 54public class SocketHandler extends StreamHandler { 55 56 // default level 57 private static final String DEFAULT_LEVEL = "ALL"; 58 59 // default formatter 60 private static final String DEFAULT_FORMATTER = "java.util.logging.XMLFormatter"; 61 62 // the socket connection 63 private Socket socket; 64 65 /** 66 * Constructs a {@code SocketHandler} object using the properties read by 67 * the log manager, including the host name and port number. Default 68 * formatting uses the XMLFormatter class and level is set to ALL. 69 * 70 * @throws IOException 71 * if failed to connect to the specified host and port. 72 * @throws IllegalArgumentException 73 * if the host name or port number is illegal. 74 */ 75 public SocketHandler() throws IOException { 76 super(DEFAULT_LEVEL, null, DEFAULT_FORMATTER, null); 77 initSocket(LogManager.getLogManager().getProperty( 78 "java.util.logging.SocketHandler.host"), LogManager 79 .getLogManager().getProperty( 80 "java.util.logging.SocketHandler.port")); 81 } 82 83 /** 84 * Constructs a {@code SocketHandler} object using the specified host name 85 * and port number together with other properties read by the log manager. 86 * Default formatting uses the XMLFormatter class and level is set to ALL. 87 * 88 * @param host 89 * the host name 90 * @param port 91 * the port number 92 * @throws IOException 93 * if failed to connect to the specified host and port. 94 * @throws IllegalArgumentException 95 * if the host name or port number is illegal. 96 */ 97 public SocketHandler(String host, int port) throws IOException { 98 super(DEFAULT_LEVEL, null, DEFAULT_FORMATTER, null); 99 initSocket(host, String.valueOf(port)); 100 } 101 102 // Initialize the socket connection and prepare the output stream 103 private void initSocket(String host, String port) throws IOException { 104 // check the validity of the host name 105 if (host == null || host.isEmpty()) { 106 throw new IllegalArgumentException("host == null || host.isEmpty()"); 107 } 108 // check the validity of the port number 109 int p = 0; 110 try { 111 p = Integer.parseInt(port); 112 } catch (NumberFormatException e) { 113 throw new IllegalArgumentException("Illegal port argument"); 114 } 115 if (p <= 0) { 116 throw new IllegalArgumentException("Illegal port argument"); 117 } 118 // establish the network connection 119 try { 120 this.socket = new Socket(host, p); 121 } catch (IOException e) { 122 getErrorManager().error("Failed to establish the network connection", e, 123 ErrorManager.OPEN_FAILURE); 124 throw e; 125 } 126 super.internalSetOutputStream(new BufferedOutputStream(this.socket.getOutputStream())); 127 } 128 129 /** 130 * Closes this handler. The network connection to the host is also closed. 131 */ 132 @Override 133 public void close() { 134 try { 135 super.close(); 136 if (this.socket != null) { 137 this.socket.close(); 138 this.socket = null; 139 } 140 } catch (Exception e) { 141 getErrorManager().error("Exception occurred when closing the socket handler", e, 142 ErrorManager.CLOSE_FAILURE); 143 } 144 } 145 146 /** 147 * Logs a record if necessary. A flush operation will be done afterwards. 148 * 149 * @param record 150 * the log record to be logged. 151 */ 152 @Override 153 public void publish(LogRecord record) { 154 super.publish(record); 155 super.flush(); 156 } 157} 158