This repository has been archived by the owner on Jun 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Retry network writes until buffers are empty #96
A high write volume can cause package loss when using TCP or UDP senders. This is because of saturated send buffers. NIO channels don't block/continue writing if send buffers are full but return from the call. Inspecting the remaining buffer size is a good measure to determine whether the buffer was written entirely or whether bytes to write are left. Add synchronization to prevent GELF message interleaving. TCP and UDP senders now retry writes until the message buffer is written entirely to the Channel (send buffer). See also PR #96.
- Loading branch information
Showing
3 changed files
with
130 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
src/test/java/biz/paluch/logging/gelf/intern/sender/GelfTCPSenderIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package biz.paluch.logging.gelf.intern.sender; | ||
|
||
import static org.fest.assertions.Assertions.assertThat; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.ServerSocket; | ||
import java.net.Socket; | ||
import java.nio.ByteBuffer; | ||
import java.nio.channels.SocketChannel; | ||
import java.util.concurrent.CountDownLatch; | ||
|
||
import org.apache.commons.io.IOUtils; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.junit.Test; | ||
|
||
import biz.paluch.logging.gelf.intern.ErrorReporter; | ||
import biz.paluch.logging.gelf.intern.GelfMessage; | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Mark Paluch</a> | ||
*/ | ||
public class GelfTCPSenderIntegrationTest { | ||
|
||
private ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
|
||
@Test(timeout = 10000) | ||
public void name() throws Exception { | ||
|
||
final ServerSocket serverSocket = new ServerSocket(1234); | ||
final CountDownLatch latch = new CountDownLatch(1); | ||
serverSocket.setSoTimeout(1000); | ||
|
||
Thread thread = new Thread("GelfTCPSenderIntegrationTest-server") { | ||
|
||
@Override | ||
public void run() { | ||
|
||
try { | ||
Socket socket = serverSocket.accept(); | ||
socket.setKeepAlive(true); | ||
InputStream inputStream = socket.getInputStream(); | ||
|
||
while (!socket.isClosed()) { | ||
IOUtils.copy(inputStream, out); | ||
Thread.sleep(1); | ||
|
||
if (latch.getCount() == 0) { | ||
socket.close(); | ||
} | ||
} | ||
|
||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} catch (InterruptedException e) { | ||
} | ||
} | ||
}; | ||
|
||
try { | ||
thread.start(); | ||
|
||
SmallBufferTCPSender sender = new SmallBufferTCPSender("localhost", 1234, 1000, 1000, new ErrorReporter() { | ||
@Override | ||
public void reportError(String message, Exception e) { | ||
} | ||
}); | ||
|
||
GelfMessage gelfMessage = new GelfMessage("hello", StringUtils.repeat("hello", 100000), 1234, "7"); | ||
ByteBuffer byteBuffer = gelfMessage.toTCPBuffer(); | ||
int size = byteBuffer.remaining(); | ||
|
||
sender.sendMessage(gelfMessage); | ||
sender.close(); | ||
|
||
latch.countDown(); | ||
thread.join(); | ||
|
||
assertThat(out.size()).isEqualTo(size); | ||
|
||
} finally { | ||
thread.interrupt(); | ||
} | ||
|
||
} | ||
|
||
static class SmallBufferTCPSender extends GelfTCPSender { | ||
|
||
public SmallBufferTCPSender(String host, int port, int connectTimeoutMs, int readTimeoutMs, ErrorReporter errorReporter) | ||
throws IOException { | ||
super(host, port, connectTimeoutMs, readTimeoutMs, errorReporter); | ||
} | ||
|
||
@Override | ||
protected SocketChannel createSocketChannel(int readTimeoutMs, boolean keepAlive) throws IOException { | ||
SocketChannel socketChannel = super.createSocketChannel(readTimeoutMs, keepAlive); | ||
|
||
socketChannel.socket().setSendBufferSize(100); | ||
|
||
return socketChannel; | ||
} | ||
} | ||
} |