/// <summary> /// Construct a TCP _socket writer that writes to the given endPoint and _port. /// </summary> /// <param name="uri">Uri to open a TCP socket to.</param> /// <param name="maxQueueSize">The maximum number of log entries to queue before starting to drop entries.</param> public TcpSocketWriter(Uri uri, int maxQueueSize = 5000) { _eventQueue = new FixedSizeQueue <string>(maxQueueSize); _tokenSource = new CancellationTokenSource(); Func <Uri, Task <Stream> > tryOpenSocket = async h => { try { TcpClient client = new TcpClient(); await client.ConnectAsync(uri.Host, uri.Port); Stream stream = client.GetStream(); if (uri.Scheme.ToLower() != "tls") { return(stream); } var sslStream = new SslStream(client.GetStream(), false, null, null); await sslStream.AuthenticateAsClientAsync(uri.Host); return(sslStream); } catch (Exception e) { LoggingFailureHandler(e); throw; } }; var threadReady = new TaskCompletionSource <bool>(); Task queueListener = Task.Factory.StartNew(async() => { try { bool sslEnabled = uri.Scheme.ToLower() == "tls"; _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token); threadReady.SetResult(true); // Signal the calling thread that we are ready. string entry = null; while (_stream != null) // null indicates that the thread has been cancelled and cleaned up. { if (_tokenSource.Token.IsCancellationRequested) { _eventQueue.CompleteAdding(); // Post-condition: no further items will be added to the queue, so there will be a finite number of items to handle. while (_eventQueue.Count > 0) { entry = _eventQueue.Dequeue(); try { byte[] messsage = Encoding.UTF8.GetBytes(entry); await _stream.WriteAsync(messsage, 0, messsage.Length); await _stream.FlushAsync(); } catch (SocketException ex) { LoggingFailureHandler(ex); } } break; } if (entry == null) { entry = _eventQueue.Dequeue(_tokenSource.Token); } else { try { byte[] messsage = Encoding.UTF8.GetBytes(entry); await _stream.WriteAsync(messsage, 0, messsage.Length); await _stream.FlushAsync(); // No exception, it was sent entry = null; } catch (IOException ex) { LoggingFailureHandler(ex); _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token); } catch (SocketException ex) { LoggingFailureHandler(ex); _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token); } } } } catch (Exception e) { LoggingFailureHandler(e); } finally { if (_stream != null) { _stream.Dispose(); } _disposed.SetResult(true); } }, _tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); threadReady.Task.Wait(TimeSpan.FromSeconds(5)); }
/// <summary> /// Construct a TCP _socket writer that writes to the given endPoint and _port. /// </summary> /// <param name="uri">Uri to open a TCP socket to.</param> /// <param name="maxQueueSize">The maximum number of log entries to queue before starting to drop entries.</param> public TcpSocketWriter(Uri uri, int maxQueueSize = 5000) { _eventQueue = new FixedSizeQueue <string>(maxQueueSize); _tokenSource = new CancellationTokenSource(); Func <Uri, Stream> tryOpenSocket = h => { try { TcpClient client = new TcpClient(uri.Host, uri.Port); Stream stream = client.GetStream(); if (uri.Scheme.ToLower() != "tls") { return(stream); } var sslStream = new SslStream(client.GetStream(), false, null, null); sslStream.AuthenticateAsClient(uri.Host); return(sslStream); } catch (SocketException e) { LoggingFailureHandler(e); throw; } }; var threadReady = new TaskCompletionSource <bool>(); var queueListener = new Thread(() => { try { _stream = _reconnectPolicy.Connect(tryOpenSocket, uri, _tokenSource.Token); threadReady.SetResult(true); // Signal the calling thread that we are ready. string entry = null; while (_stream != null) // null indicates that the thread has been cancelled and cleaned up. { if (_tokenSource.Token.IsCancellationRequested) { _eventQueue.CompleteAdding(); // Post-condition: no further items will be added to the queue, so there will be a finite number of items to handle. while (_eventQueue.Count > 0) { entry = _eventQueue.Dequeue(); try { var messsage = Encoding.UTF8.GetBytes(entry); if (uri.Scheme.ToLower() == "tls") { ((SslStream)_stream).Write(messsage); } else { _stream.Write(messsage, 0, messsage.Length); _stream.Flush(); } } catch (SocketException ex) { LoggingFailureHandler(ex); } } break; } if (entry == null) { entry = _eventQueue.Dequeue(_tokenSource.Token); } else { try { var messsage = Encoding.UTF8.GetBytes(entry); if (uri.Scheme.ToLower() == "tls") { ((SslStream)_stream).Write(messsage); } else { _stream.Write(messsage, 0, messsage.Length); } _stream.Flush(); // No exception, it was sent entry = null; } catch (SocketException ex) { LoggingFailureHandler(ex); _stream = _reconnectPolicy.Connect(tryOpenSocket, uri, _tokenSource.Token); } } } } catch (Exception e) { LoggingFailureHandler(e); } finally { if (_stream != null) { _stream.Close(); _stream.Dispose(); } _disposed.SetResult(true); } }) { IsBackground = true }; // Prevent the thread from blocking the process from exiting. queueListener.Start(); threadReady.Task.Wait(TimeSpan.FromSeconds(5)); }