11package com .rapid7 .jul ;
22
3- import java .io .IOException ;
4- import java .net .InetSocketAddress ;
5- import java .nio .BufferOverflowException ;
6- import java .nio .ByteBuffer ;
7- import java .nio .channels .SocketChannel ;
8- import java .nio .charset .Charset ;
3+ import com .rapid7 .net .AsyncLogger ;
4+ import com .rapid7 .net .LoggerConfiguration ;
5+
96import java .text .MessageFormat ;
107import java .util .logging .Formatter ;
118import java .util .logging .Handler ;
1411import java .util .logging .LogRecord ;
1512import java .util .logging .SimpleFormatter ;
1613
17- import static com .google .common .base .Strings .isNullOrEmpty ;
18- import static com .rapid7 .Constants .DATA_ENDPOINT_TEMPLATE ;
19- import static java .util .logging .ErrorManager .CLOSE_FAILURE ;
2014import static java .util .logging .ErrorManager .FORMAT_FAILURE ;
2115import static java .util .logging .ErrorManager .GENERIC_FAILURE ;
22- import static java .util .logging .ErrorManager .OPEN_FAILURE ;
23- import static java .util .logging .ErrorManager .WRITE_FAILURE ;
2416
25- /**
26- * <code>LogentriesHandler</code>: A handler for writing formatted records to a
27- * logentries.com. This handler uses the Token-based input.
28- *
29- * @author Björn Raupach (raupach@me.com)
30- */
31- public final class LogentriesHandler extends Handler {
17+ public class LogentriesHandler extends Handler {
3218
33- private final byte [] newline = {0x0D , 0x0A };
34- private final byte space = 0x020 ;
35- private String host ;
36- private int port ;
37- private byte [] token ;
38- private String region ;
39- private boolean open ;
40- private SocketChannel channel ;
41- private ByteBuffer buffer ;
19+ /**
20+ * Asynchronous Background logger
21+ */
22+ final AsyncLogger iopsAsync ;
4223
4324 public LogentriesHandler () {
4425 this (null );
4526 }
4627
4728 public LogentriesHandler (String prefix ) {
48- configure (prefix );
49- connect ();
50- buffer = ByteBuffer .allocate (4096 );
51- }
52-
53- public String getHost () {
54- return host ;
55- }
56-
57- public void setHost (String host ) {
58- this .host = host ;
59- }
60-
61- public int getPort () {
62- return port ;
29+ iopsAsync = new AsyncLogger (loadConfiguration (prefix ));
6330 }
6431
65- public void setPort (int port ) {
66- this .port = port ;
67- }
68-
69- public byte [] getToken () {
70- return token ;
71- }
72-
73- public void setToken (byte [] token ) {
74- this .token = token ;
75- }
76-
77- public String getRegion () {
78- return region ;
79- }
80-
81- public void setRegion (String region ) {
82- this .region = region ;
32+ private LoggerConfiguration loadConfiguration (String prefix ) {
33+ String cname = getClass ().getName ();
34+ String propsPrefix = prefix == null ? cname : prefix + "." + cname ;
35+ setLevel (getLevelProperty (propsPrefix + ".level" , Level .INFO ));
36+ setFormatter (getFormatterProperty (propsPrefix + ".formatter" , new SimpleFormatter ()));
37+ return new LoggerConfiguration .Builder ()
38+ .inRegion (getStringProperty (propsPrefix + ".region" , "" ))
39+ .toServerAddress (getStringProperty (propsPrefix + ".host" , null ))
40+ .toServerPort (getIntProperty (propsPrefix + ".port" , 0 ))
41+ .useToken (getStringProperty (propsPrefix + ".token" , "" ))
42+ .useDataHub (getBooleanProperty (propsPrefix + ".useDataHub" , false ))
43+ .useHttpPut (getBooleanProperty (propsPrefix + ".httpPut" , false ))
44+ .useAccountKey (getStringProperty (propsPrefix + ".key" , "" ))
45+ .httpPutLocation (getStringProperty (propsPrefix + ".location" , "" ))
46+ .runInDebugMode (getBooleanProperty (propsPrefix + ".debug" , false ))
47+ .logHostNameAsPrefix (getBooleanProperty (propsPrefix + ".logHostName" , false ))
48+ .useAsHostName (getStringProperty (propsPrefix + ".hostNameToLog" , "" ))
49+ .setLogIdPrefix (getStringProperty (propsPrefix + ".logId" , "" ))
50+ .useSSL (getBooleanProperty (propsPrefix + ".ssl" , true ))
51+ .build ();
8352 }
8453
8554
8655 @ Override
8756 public synchronized void publish (LogRecord record ) {
88- if (open && isLoggable (record )) {
89- String msg = formatMessage (record );
90- if (!msg .isEmpty ()) {
91- boolean filled = fillAndFlip (msg );
92- if (filled ) {
93- boolean drained = drain ();
94- if (!drained ) {
95- System .err .println ("java.util.logging.ErrorManager: Sending to logentries.com failed. Trying to reconnect once." );
96- connect ();
97- if (open ) {
98- filled = fillAndFlip (msg );
99- if (filled ) {
100- drained = drain ();
101- if (!drained ) {
102- System .err .println ("java.util.logging.ErrorManager: Unable to reconnect. Shutting handler down." );
103- close ();
104- }
105- }
106- }
107- }
108- }
109- }
57+ if (isLoggable (record )) {
58+ this .iopsAsync .addLineToQueue (formatMessage (record ));
11059 }
11160 }
11261
@@ -122,77 +71,14 @@ String formatMessage(LogRecord record) {
12271 return msg ;
12372 }
12473
125- boolean fillAndFlip (String formattedMessage ) {
126- try {
127- buffer .clear ();
128- buffer .put (token );
129- buffer .put (space );
130- buffer .put (formattedMessage .getBytes (Charset .forName ("UTF-8" )));
131- buffer .put (newline );
132- } catch (BufferOverflowException e ) {
133- reportError ("Buffer exceeds capacity" , e , WRITE_FAILURE );
134- return false ;
135- }
136- buffer .flip ();
137- return true ;
138- }
139-
140- boolean drain () {
141- while (buffer .hasRemaining ()) {
142- try {
143- channel .write (buffer );
144- } catch (Exception e ) {
145- reportError ("Error while writing channel." , e , WRITE_FAILURE );
146- return false ;
147- }
148- }
149- return true ;
150- }
151-
152- void configure (String prefix ) {
153- String cname = getClass ().getName ();
154- String propsPrefix = prefix == null ? cname : prefix + "." + cname ;
155- setLevel (getLevelProperty (propsPrefix + ".level" , Level .INFO ));
156- setFormatter (getFormatterProperty (propsPrefix + ".formatter" , new SimpleFormatter ()));
157- setRegion (getStringProperty (propsPrefix + ".region" , "" ));
158-
159- String hostProperty = getStringProperty (propsPrefix + ".host" , null );
160- if (isNullOrEmpty (hostProperty )) {
161- setHost (String .format (DATA_ENDPOINT_TEMPLATE , region ));
162- } else {
163- setHost (hostProperty );
164- }
165-
166- setPort (getIntProperty (propsPrefix + ".port" , 514 ));
167- setToken (getBytesProperty (propsPrefix + ".token" , "" ));
168- }
169-
170- void connect () {
171- try {
172- channel = SocketChannel .open ();
173- channel .connect (new InetSocketAddress (host , port ));
174- open = true ;
175- } catch (IOException e ) {
176- open = false ;
177- reportError (MessageFormat .format ("Error connection to host: {0}:{1}" , host , port ), e , OPEN_FAILURE );
178- }
179- }
180-
18174 @ Override
18275 public void flush () {
76+ // no need to flush since the log is sent by AsyncLogger
18377 }
18478
18579 @ Override
186- public void close () throws SecurityException {
187- open = false ;
188- buffer = null ;
189- if (channel != null ) {
190- try {
191- channel .close ();
192- } catch (IOException e ) {
193- reportError ("Error while closing channel." , e , CLOSE_FAILURE );
194- }
195- }
80+ public void close () {
81+ iopsAsync .close ();
19682 }
19783
19884 // -- These methods are private in LogManager
@@ -235,8 +121,20 @@ String getStringProperty(String name, String defaultValue) {
235121 return val .trim ();
236122 }
237123
238- byte [] getBytesProperty (String name , String defaultValue ) {
239- return getStringProperty (name , defaultValue ).getBytes ();
124+ boolean getBooleanProperty (String name , boolean defaultValue ) {
125+ LogManager manager = LogManager .getLogManager ();
126+ String val = manager .getProperty (name );
127+ if (val == null ) {
128+ return defaultValue ;
129+ }
130+ if ("false" .equalsIgnoreCase (val .trim ())) {
131+ return false ;
132+ } else if ("true" .equalsIgnoreCase (val .trim ())) {
133+ return true ;
134+ } else {
135+ reportError (MessageFormat .format ("Error reading property ''{0}''" , name ), null , GENERIC_FAILURE );
136+ return defaultValue ;
137+ }
240138 }
241139
242140 int getIntProperty (String name , int defaultValue ) {
0 commit comments