/// <summary> /// Constructor. /// </summary> /// <param name="host">Hostname to log to.</param> /// <param name="port">Port on remote host.</param> /// <param name="policy">An object embodying a reconnection policy for if the /// TCP session drops (defaults to ExponentialBackoffTcpConnectionPolicy).</param> /// <param name="maxQueueSize">The maximum number of events to queue if the /// TCP session goes down. If more events are queued, old ones will be dropped /// (defaults to 10,000).</param> /// <param name="progress">An IProgress instance that will be triggered when /// an event is pulled from the queue and written to the TCP port (defaults to a new /// Progress object accessible via the Progress property).</param> public TcpTraceListener(string host, int port, ITcpReconnectionPolicy policy, int maxQueueSize = 10000) : this(host.HostnameToIPAddress(), port, policy, maxQueueSize) { }
/// <summary> /// Construct a TCP socket writer that writes to the given host and port. /// </summary> /// <param name="host">IPAddress of the host to open a TCP socket to.</param> /// <param name="port">TCP port to use on the target host.</param> /// <param name="policy">A TcpConnectionPolicy object defining reconnect behavior.</param> /// <param name="maxQueueSize">The maximum number of log entries to queue before starting to drop entries.</param> /// <param name="progress">An IProgress object that reports when the queue of entries to be written reaches empty or there is /// a reconnection failure. This is used for testing purposes only.</param> public TcpSocketWriter(IPAddress host, int port, ITcpReconnectionPolicy policy, int maxQueueSize, Func <IPAddress, int, Socket> connect = null) { this.host = host; this.port = port; this.reconnectPolicy = policy; this.eventQueue = new FixedSizeQueue <string>(maxQueueSize); this.tokenSource = new CancellationTokenSource(); if (connect == null) { this.tryOpenSocket = (h, p) => { try { var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Connect(host, port); return(socket); } catch (SocketException e) { LoggingFailureHandler(e); throw; } }; } else { this.tryOpenSocket = (h, p) => { try { return(connect(h, p)); } catch (SocketException e) { LoggingFailureHandler(e); throw; } }; } var threadReady = new TaskCompletionSource <bool>(); queueListener = new Thread(() => { try { this.socket = this.reconnectPolicy.Connect(tryOpenSocket, host, port, tokenSource.Token); threadReady.SetResult(true); // Signal the calling thread that we are ready. string entry = null; while (this.socket != 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 { this.socket.Send(Encoding.UTF8.GetBytes(entry)); } catch (SocketException ex) { LoggingFailureHandler(ex); } } break; } else if (entry == null) { entry = eventQueue.Dequeue(tokenSource.Token); } else if (entry != null) { try { if (this.socket.Send(Encoding.UTF8.GetBytes(entry)) != -1) { entry = null; } } catch (SocketException ex) { LoggingFailureHandler(ex); this.socket = this.reconnectPolicy.Connect(tryOpenSocket, host, port, tokenSource.Token); } } } } catch (Exception e) { LoggingFailureHandler(e); } finally { if (socket != null) { socket.Dispose(); } disposed.SetResult(true); } }); queueListener.IsBackground = true; // Prevent the thread from blocking the process from exiting. queueListener.Start(); threadReady.Task.Wait(); }
/// <summary> /// Constructor. /// </summary> /// <param name="host">IP address to log to.</param> /// <param name="port">Port on remote host.</param> /// <param name="policy">An object embodying a reconnection policy for if the /// TCP session drops (defaults to ExponentialBackoffTcpConnectionPolicy).</param> /// <param name="maxQueueSize">The maximum number of events to queue if the /// TCP session goes down. If more events are queued, old ones will be dropped /// (defaults to 10,000).</param> /// <param name="progress">An IProgress instance that will be triggered when /// an event is pulled from the queue and written to the TCP port (defaults to a new /// Progress object accessible via the Progress property).</param> public TcpTraceListener(IPAddress host, int port, ITcpReconnectionPolicy policy, int maxQueueSize = 10000) : base() { this.writer = new TcpSocketWriter(host, port, policy, maxQueueSize); }
/// <summary> /// Set up a sink. /// </summary> /// <param name="host">Hostname of the host to write to.</param> /// <param name="port">TCP port to write to.</param> /// <param name="formatter">An object to specify the format events should be /// written in (default to <code>{timestamp} EventId={...} EventName={...} Level={...} "FormattedMessage={...}"</code>).</param> /// <param name="policy">An object defining the reconnect policy in the event /// of TCP errors (default: an ExponentialBackoffTcpConnectionPolicy object).</param> /// <param name="maxQueueSize">The maximum number of events to queue in the event of /// the TCP session dropping before events start to be dropped (defaults to 10,000).</param> /// <param name="progress">A progress reporter that triggers when events are written from /// the queue to the TCP port (defaults to a new Progress object). It is reachable /// via the Progress property.</param> public TcpEventSink(string host, int port, ITcpReconnectionPolicy policy, IEventTextFormatter formatter = null, int maxQueueSize = 10000) : this(host.HostnameToIPAddress(), port, policy, formatter, maxQueueSize) { }
/// <summary> /// Set up a sink. /// </summary> /// <param name="host">IP address of the host to write to.</param> /// <param name="port">TCP port to write to.</param> /// <param name="formatter">An object to specify the format events should be /// written in (defaults to <code>{timestamp} EventId={...} EventName={...} Level={...} "FormattedMessage={...}"</code>).</param> /// <param name="policy">An object defining the reconnect policy in the event /// of TCP errors (default: an ExponentialBackoffTcpConnectionPolicy object).</param> /// <param name="maxQueueSize">The maximum number of events to queue in the event of /// the TCP session dropping before events start to be dropped (defaults to 10,000).</param> /// <param name="progress">A progress reporter that triggers when events are written from /// the queue to the TCP port (defaults to a new Progress object). It is reachable /// via the Progress property.</param> public TcpEventSink(IPAddress host, int port, ITcpReconnectionPolicy policy, IEventTextFormatter formatter = null, int maxQueueSize = 10000) { this.writer = new TcpSocketWriter(host, port, policy, maxQueueSize); this.formatter = formatter; }