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
18 package org.apache.log4j.net;
19
20 import java.io.Writer;
21 import java.net.DatagramSocket;
22 import java.net.InetAddress;
23 import java.net.DatagramPacket;
24 import java.net.UnknownHostException;
25 import java.net.SocketException;
26 import java.io.IOException;
27
28 import org.apache.log4j.helpers.LogLog;
29
30 /**
31 * DatagramStringWriter is a wrapper around the java.net.DatagramSocket class
32 * so that it behaves like a java.io.Writer.
33 */
34 public class DatagramStringWriter extends Writer {
35
36 static final int SYSLOG_PORT = 514;
37
38 private int port;
39 private String host;
40 private String encoding;
41 private String prefix;
42
43 private InetAddress address;
44 private DatagramSocket ds;
45
46 /**
47 * This constructor assumes that it is sending to a remote syslog daemon
48 * on the normal syslog port (514), and uses the default platform character
49 * encoding when converting the message string to a byte sequence.
50 */
51 public
52 DatagramStringWriter(String host) {
53 this(host, SYSLOG_PORT, null, null);
54 }
55
56 /**
57 * This constructor sends messages to the specified host and port, and
58 * uses the default platform character encoding when converting the message
59 * string to a byte sequence.
60 */
61 public
62 DatagramStringWriter(String host, int port) {
63 this(host, port, null, null);
64 }
65
66 /**
67 * This constructor sends messages to the specified host and port, and
68 * uses the specified character encoding when converting the message
69 * string to a byte sequence.
70 */
71 public
72 DatagramStringWriter(String host, int port, String encoding) {
73 this(host, port, null, null);
74 }
75 /**
76 * This constructor sends messages to the specified host and port, and
77 * uses the specified character encoding when converting the message
78 * string to a byte sequence; the specified prefix (which may be null)
79 * is prepended to each message.
80 */
81 public
82 DatagramStringWriter(String host, int port, String encoding, String prefix) {
83 this.host = host;
84 this.port = port;
85 this.encoding = encoding;
86 this.prefix = prefix;
87
88 try {
89 this.address = InetAddress.getByName(host);
90 }
91 catch (UnknownHostException e) {
92 LogLog.error("Could not find " + host +
93 ". All logging will FAIL.", e);
94 }
95
96 try {
97 this.ds = new DatagramSocket();
98 }
99 catch (SocketException e) {
100 e.printStackTrace();
101 LogLog.error("Could not instantiate DatagramSocket to " + host +
102 ". All logging will FAIL.", e);
103 }
104 }
105
106
107 public
108 void write(char[] buf, int off, int len) throws IOException {
109 this.write(new String(buf, off, len));
110 }
111
112 public
113 void write(String string) throws IOException {
114 if (prefix != null) {
115 string = prefix + string;
116 }
117
118 byte[] rawData;
119 if (this.encoding == null)
120 {
121 // convert to byte sequence using platform's default encoding
122 rawData = string.getBytes();
123 }
124 else
125 {
126 // convert to specified encoding - which may be sequence of
127 // 8-bit chars, or multi-byte encodings like UTF-8 or UTF-16.
128 // The receiving end had better be expecting whatever encoding
129 // is used here on the sending end!
130 rawData = string.getBytes(encoding);
131 }
132
133 DatagramPacket packet =
134 new DatagramPacket(
135 rawData,
136 rawData.length,
137 address,
138 port);
139
140 if(this.ds != null)
141 {
142 ds.send(packet);
143 }
144 else
145 {
146 LogLog.error(
147 "write: failed to create DatagramPacket");
148 }
149 }
150
151 public
152 void flush() {}
153
154 public
155 void close() {}
156
157 /**
158 * Set a string to be prefixed to every message sent by this Writer.
159 * For example, this method could be used to prepend a syslog
160 * facility/priority code on the front of each message.
161 * <p>
162 * Note that this method is not synchronised, so should not be called in
163 * a situation where other threads may be logging messages at the same
164 * moment.
165 * <p>
166 * @param prefix may be a prefix string, or null which indicates no
167 * prefix should be added.
168 */
169 public
170 void setPrefix(String prefix){
171 this.prefix = prefix;
172 }
173 }