private bool DoWithReconnect(ref LogEntriesConnection connection, byte[] token, string entry, out Exception error) { var success = false; error = null; try { if (!connection.IsIdleForTooLong) { LogEntryWriter.Write(token, entry, connection); success = true; } } catch (Exception ex) { error = ex; } if (!success) { Reconnect(ref connection); } return(success); }
internal static void Write(byte[] token, string entry, LogEntriesConnection connection) { Array.Copy(token, 0, _buffer, 0, token.Length); var buffered = token.Length; var readed = 0; while (readed != entry.Length) { ReplaceAndBufferChars(entry, readed, _charBuffer, out int used, out int formatted); readed += used; var completed = false; var totalCharsUsed = 0; var bytesUsed = 0; while (!completed) { _encoding.Convert( chars: _charBuffer, charIndex: totalCharsUsed, charCount: formatted - totalCharsUsed, bytes: _buffer, byteIndex: buffered, byteCount: _buffer.Length - buffered, flush: formatted == totalCharsUsed, charsUsed: out int charsUsed, bytesUsed: out bytesUsed, completed: out completed); buffered += bytesUsed; totalCharsUsed += charsUsed; if (completed && readed == entry.Length) { if (buffered < _buffer.Length) { _buffer[buffered++] = _newLineByte; } else // data fits the end of the buffer so in order to { // send the end line delimitator \n it is needed to // clean the buffer. This may occur very little times. connection.Send(_buffer, buffered); _buffer[0] = _newLineByte; buffered = 1; } } connection.Send(_buffer, buffered); buffered = 0; } } }
private void Reconnect(ref LogEntriesConnection connection) { connection?.Dispose(); connection = null; while (connection == null && _closed == 0) { try { connection = new LogEntriesConnection(); } catch (Exception ex) // Unable to connect to Logentries. { Trace.WriteLine($"Connection failed: {ex.Message}."); Thread.Sleep(LogEntriesSettings.PauseBetweenReconnections); } } }
private void MasterConsumeAndSendEvents() { LogEntriesConnection connection = null; try { Reconnect(ref connection); foreach (var datas in _queue.GetConsumingEnumerable()) { DoWithRetry(ref connection, datas.Item1, datas.Item2); UpscaleIfNeeded(); } } finally { connection?.Dispose(); } }
private void DoWithRetry(ref LogEntriesConnection connection, byte[] token, string entry) { var retry = 0; var error = (Exception)null; while (!DoWithReconnect(ref connection, token, entry, out error)) { retry++; if (retry >= LogEntriesSettings.MaxRetries) { // At least try to signal that the component was unable to save // the entry. In case it is because this component fault, the error // would be recorded somewhere. error = error ?? new Exception("No error provided"); DoWithReconnect(ref connection, token, $"[NLog.Contrib.Targets.LogEntries] Entry Dropped because: ({error.GetType().Name}): {error.Message} \n {error.StackTrace}", out error); return; } } }
private void ConsumeAndSendEvents() { LogEntriesConnection connection = null; try { Reconnect(ref connection); foreach (var datas in _queue.GetConsumingEnumerable()) { DoWithRetry(ref connection, datas.Item1, datas.Item2); Trace.Write("."); if (!ContinueConsuming()) { Interlocked.Decrement(ref _additionalThreadCount); Trace.WriteLine($"Removed thread. Current count {_additionalThreadCount}. State {(_closed== 1?"closed":"running")}. Queue {_queue.Count}."); return; } } } finally { connection?.Dispose(); } }