87 lines
2.8 KiB
C#
87 lines
2.8 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace StatsdClient
|
|
{
|
|
internal sealed class TcpOutputChannel : IOutputChannel
|
|
{
|
|
private readonly TcpClient _tcpClient;
|
|
private NetworkStream _stream;
|
|
private readonly string _host;
|
|
private readonly int _port;
|
|
private readonly bool _reconnectEnabled;
|
|
private readonly int _retryAttempts;
|
|
private readonly AsyncLock _asyncLock;
|
|
|
|
public TcpOutputChannel(string host, int port, bool reconnectEnabled = true, int retryAttempts = 3)
|
|
{
|
|
_host = host;
|
|
_port = port;
|
|
_reconnectEnabled = reconnectEnabled;
|
|
_retryAttempts = retryAttempts;
|
|
_tcpClient = new TcpClient();
|
|
_asyncLock = new AsyncLock();
|
|
}
|
|
|
|
public async Task SendAsync(string line)
|
|
{
|
|
await SendWithRetryAsync(line, _reconnectEnabled ? _retryAttempts - 1 : 0);
|
|
}
|
|
|
|
private async Task SendWithRetryAsync(string line, int attemptsLeft)
|
|
{
|
|
string errorMessage = null;
|
|
try
|
|
{
|
|
if (!_tcpClient.Connected)
|
|
{
|
|
await RestoreConnectionAsync();
|
|
}
|
|
|
|
var bytesToSend = Encoding.UTF8.GetBytes(line + Environment.NewLine);
|
|
await _stream.WriteAsync(bytesToSend, 0, bytesToSend.Length);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
errorMessage = string.Format("Sending metrics via TCP failed with an IOException: {0}", ex.Message);
|
|
}
|
|
catch (SocketException ex)
|
|
{
|
|
// No more attempts left, so log it and continue
|
|
errorMessage = string.Format("Sending metrics via TCP failed with a SocketException: {0}, code: {1}", ex.Message, ex.SocketErrorCode);
|
|
}
|
|
|
|
if (errorMessage != null)
|
|
{
|
|
if (attemptsLeft > 0)
|
|
{
|
|
await SendWithRetryAsync(line, --attemptsLeft);
|
|
}
|
|
else
|
|
{
|
|
// No more attempts left, so log it and continue
|
|
Trace.TraceWarning(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task RestoreConnectionAsync()
|
|
{
|
|
if (!_tcpClient.Connected)
|
|
{
|
|
using (await _asyncLock.LockAsync())
|
|
{
|
|
if (!_tcpClient.Connected)
|
|
{
|
|
await _tcpClient.ConnectAsync(_host, _port);
|
|
_stream = _tcpClient.GetStream();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |