/// <summary> /// Writes an array of logging events to the log target. By default it iterates on all /// events and passes them to "Write" method. Inheriting classes can use this method to /// optimize batch writes. /// </summary> /// <param name="logEvents">Logging events to be written out.</param> protected override void Write(AsyncLogEventInfo[] logEvents) { InternalLogger.Trace("Writing {0} events", logEvents.Length); for (var i = 0; i < logEvents.Length; ++i) { logEvents[i].Continuation = CountedWrap(logEvents[i].Continuation, Targets.Count); } foreach (var t in Targets) { InternalLogger.Trace("Sending {0} events to {1}", logEvents.Length, t); t.WriteAsyncLogEvents(logEvents); } }
/// <summary> /// Forwards the log event to one of the sub-targets. /// The sub-target is randomly chosen. /// </summary> /// <param name="logEvent">The log event.</param> protected override void Write(AsyncLogEventInfo logEvent) { if (Targets.Count == 0) { logEvent.Continuation(null); return; } int selectedTarget; lock (random) { selectedTarget = random.Next(Targets.Count); } Targets[selectedTarget].WriteAsyncLogEvent(logEvent); }
/// <summary> /// Forwards the write to one of the targets from /// the <see cref="NLog.Targets" /> collection. /// </summary> /// <param name="logEvent">The log event.</param> /// <remarks> /// The writes are routed in a round-robin fashion. /// The first log event goes to the first target, the second /// one goes to the second target and so on looping to the /// first target when there are no more targets available. /// In general request N goes to Targets[N % Targets.Count]. /// </remarks> protected override void Write(AsyncLogEventInfo logEvent) { if (Targets.Count == 0) { logEvent.Continuation(null); return; } int selectedTarget; lock (lockObject) { selectedTarget = currentTarget; currentTarget = (currentTarget + 1)%Targets.Count; } Targets[selectedTarget].WriteAsyncLogEvent(logEvent); }
/// <summary> /// Adds the specified log event to the buffer. /// </summary> /// <param name="eventInfo">Log event.</param> /// <returns>The number of items in the buffer.</returns> public int Append(AsyncLogEventInfo eventInfo) { lock (this) { // make room for additional item if (count >= buffer.Length) { if (growAsNeeded && buffer.Length < growLimit) { // create a new buffer, copy data from current var newLength = buffer.Length*2; if (newLength >= growLimit) { newLength = growLimit; } // InternalLogger.Trace("Enlarging LogEventInfoBuffer from {0} to {1}", this.buffer.Length, this.buffer.Length * 2); var newBuffer = new AsyncLogEventInfo[newLength]; Array.Copy(buffer, 0, newBuffer, 0, buffer.Length); buffer = newBuffer; } else { // lose the oldest item getPointer = getPointer + 1; } } // put the item putPointer = putPointer%buffer.Length; buffer[putPointer] = eventInfo; putPointer = putPointer + 1; count++; if (count >= buffer.Length) { count = buffer.Length; } return count; } }
/// <summary> /// Adds the specified log event to the buffer. /// </summary> /// <param name="eventInfo">Log event.</param> /// <returns>The number of items in the buffer.</returns> public int Append(AsyncLogEventInfo eventInfo) { lock (this) { // make room for additional item if (count >= buffer.Length) { if (growAsNeeded && buffer.Length < growLimit) { // create a new buffer, copy data from current var newLength = buffer.Length * 2; if (newLength >= growLimit) { newLength = growLimit; } // InternalLogger.Trace("Enlarging LogEventInfoBuffer from {0} to {1}", this.buffer.Length, this.buffer.Length * 2); var newBuffer = new AsyncLogEventInfo[newLength]; Array.Copy(buffer, 0, newBuffer, 0, buffer.Length); buffer = newBuffer; } else { // lose the oldest item getPointer = getPointer + 1; } } // put the item putPointer = putPointer % buffer.Length; buffer[putPointer] = eventInfo; putPointer = putPointer + 1; count++; if (count >= buffer.Length) { count = buffer.Length; } return(count); } }
/// <summary> /// Gets the array of events accumulated in the buffer and clears the buffer as one atomic operation. /// </summary> /// <returns>Events in the buffer.</returns> public AsyncLogEventInfo[] GetEventsAndClear() { lock (this) { var cnt = count; var returnValue = new AsyncLogEventInfo[cnt]; // InternalLogger.Trace("GetEventsAndClear({0},{1},{2})", this.getPointer, this.putPointer, this.count); for (var i = 0; i < cnt; ++i) { var p = (getPointer + i) % buffer.Length; var e = buffer[p]; buffer[p] = default(AsyncLogEventInfo); // we don't want memory leaks returnValue[i] = e; } count = 0; getPointer = 0; putPointer = 0; return(returnValue); } }
/// <summary> /// Gets the array of events accumulated in the buffer and clears the buffer as one atomic operation. /// </summary> /// <returns>Events in the buffer.</returns> public AsyncLogEventInfo[] GetEventsAndClear() { lock (this) { var cnt = count; var returnValue = new AsyncLogEventInfo[cnt]; // InternalLogger.Trace("GetEventsAndClear({0},{1},{2})", this.getPointer, this.putPointer, this.count); for (var i = 0; i < cnt; ++i) { var p = (getPointer + i)%buffer.Length; var e = buffer[p]; buffer[p] = default(AsyncLogEventInfo); // we don't want memory leaks returnValue[i] = e; } count = 0; getPointer = 0; putPointer = 0; return returnValue; } }
/// <summary> /// Sends the /// rendered logging event over the network optionally concatenating it with a newline character. /// </summary> /// <param name="logEvent">The logging event.</param> protected override void Write(AsyncLogEventInfo logEvent) { var address = Address.Render(logEvent.LogEvent); var bytes = GetBytesToWrite(logEvent.LogEvent); if (KeepConnection) { var sender = GetCachedNetworkSender(address); ChunkedSend( sender, bytes, ex => { if (ex != null) { InternalLogger.Error("Error when sending {0}", ex); ReleaseCachedConnection(sender); } logEvent.Continuation(ex); }); } else { var sender = SenderFactory.Create(address); sender.Initialize(); lock (openNetworkSenders) { openNetworkSenders.Add(sender); ChunkedSend( sender, bytes, ex => { lock (openNetworkSenders) { openNetworkSenders.Remove(sender); } if (ex != null) { InternalLogger.Error("Error when sending {0}", ex); } sender.Close(ex2 => { }); logEvent.Continuation(ex); }); } } }
/// <summary> /// Forwards the log event to the sub-targets until one of them succeeds. /// </summary> /// <param name="logEvent">The log event.</param> /// <remarks> /// The method remembers the last-known-successful target /// and starts the iteration from it. /// If <see cref="ReturnToFirstOnSuccess" /> is set, the method /// resets the target to the first target /// stored in <see cref="NLog.Targets" />. /// </remarks> protected override void Write(AsyncLogEventInfo logEvent) { AsyncContinuation continuation = null; var tryCounter = 0; int targetToInvoke; continuation = ex => { if (ex == null) { // success lock (lockObject) { if (currentTarget != 0) { if (ReturnToFirstOnSuccess) { InternalLogger.Debug("Fallback: target '{0}' succeeded. Returning to the first one.", Targets[currentTarget]); currentTarget = 0; } } } logEvent.Continuation(null); return; } // failure lock (lockObject) { InternalLogger.Warn("Fallback: target '{0}' failed. Proceeding to the next one. Error was: {1}", Targets[currentTarget], ex); // error while writing, go to the next one currentTarget = (currentTarget + 1)%Targets.Count; tryCounter++; targetToInvoke = currentTarget; if (tryCounter >= Targets.Count) { targetToInvoke = -1; } } if (targetToInvoke >= 0) { Targets[targetToInvoke].WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(continuation)); } else { logEvent.Continuation(ex); } }; lock (lockObject) { targetToInvoke = currentTarget; } Targets[targetToInvoke].WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(continuation)); }
/// <summary> /// Writes an array of logging events to the log target. By default it iterates on all /// events and passes them to "Write" method. Inheriting classes can use this method to /// optimize batch writes. /// </summary> /// <param name="logEvents">Logging events to be written out.</param> protected override void Write(AsyncLogEventInfo[] logEvents) { var buckets = logEvents.BucketSort(c => BuildConnectionString(c.LogEvent)); try { foreach (var kvp in buckets) { foreach (var ev in kvp.Value) { try { WriteEventToDatabase(ev.LogEvent); ev.Continuation(null); } catch (Exception exception) { if (exception.MustBeRethrown()) { throw; } // in case of exception, close the connection and report it InternalLogger.Error("Error when writing to database {0}", exception); CloseConnection(); ev.Continuation(exception); } } } } finally { if (!KeepConnection) { CloseConnection(); } } }
/// <summary> /// Adds the log event to asynchronous queue to be processed by /// the lazy writer thread. /// </summary> /// <param name="logEvent">The log event.</param> /// <remarks> /// The <see cref="Target.PrecalculateVolatileLayouts" /> is called /// to ensure that the log event can be processed in another thread. /// </remarks> protected override void Write(AsyncLogEventInfo logEvent) { PrecalculateVolatileLayouts(logEvent.LogEvent); RequestQueue.Enqueue(logEvent); }
internal void WriteAsyncLogEvents(AsyncLogEventInfo[] logEventInfos, AsyncContinuation continuation) { if (logEventInfos.Length == 0) { continuation(null); } else { var wrappedLogEventInfos = new AsyncLogEventInfo[logEventInfos.Length]; var remaining = logEventInfos.Length; for (var i = 0; i < logEventInfos.Length; ++i) { var originalContinuation = logEventInfos[i].Continuation; AsyncContinuation wrappedContinuation = ex => { originalContinuation(ex); if (0 == Interlocked.Decrement(ref remaining)) { continuation(null); } }; wrappedLogEventInfos[i] = logEventInfos[i].LogEvent.WithContinuation(wrappedContinuation); } WriteAsyncLogEvents(wrappedLogEventInfos); } }
/// <summary> /// Changes the security context, forwards the call to the <see cref="WrapperTargetBase.WrappedTarget" />.Write() /// and switches the context back to original. /// </summary> /// <param name="logEvents">Log events.</param> protected override void Write(AsyncLogEventInfo[] logEvents) { using (DoImpersonate()) { WrappedTarget.WriteAsyncLogEvents(logEvents); } }
/// <summary> /// Forwards the call to the <see cref="WrapperTargetBase.WrappedTarget" />.Write() /// and calls <see cref="Target.Flush(AsyncContinuation)" /> on it. /// </summary> /// <param name="logEvent">Logging event to be written out.</param> protected override void Write(AsyncLogEventInfo logEvent) { WrappedTarget.WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(AsyncHelpers.PrecededBy(logEvent.Continuation, WrappedTarget.Flush))); }
/// <summary> /// Writes the array of log events. /// </summary> /// <param name="logEvents">The log events.</param> public void WriteAsyncLogEvents(params AsyncLogEventInfo[] logEvents) { lock (SyncRoot) { if (!IsInitialized) { foreach (var ev in logEvents) { ev.Continuation(null); } return; } if (initializeException != null) { foreach (var ev in logEvents) { ev.Continuation(CreateInitException()); } return; } var wrappedEvents = new AsyncLogEventInfo[logEvents.Length]; for (var i = 0; i < logEvents.Length; ++i) { wrappedEvents[i] = logEvents[i].LogEvent.WithContinuation(AsyncHelpers.PreventMultipleCalls(logEvents[i].Continuation)); } try { Write(wrappedEvents); } catch (Exception exception) { if (exception.MustBeRethrown()) { throw; } // in case of synchronous failure, assume that nothing is running asynchronously foreach (var ev in wrappedEvents) { ev.Continuation(exception); } } } }
/// <summary> /// Renders an array logging events. /// </summary> /// <param name="logEvents">Array of logging events.</param> protected override void Write(AsyncLogEventInfo[] logEvents) { foreach (var bucket in logEvents.BucketSort(c => GetSmtpSettingsKey(c.LogEvent))) { var eventInfos = bucket.Value; ProcessSingleMailMessage(eventInfos); } }
/// <summary> /// Enqueues another item. If the queue is overflown the appropriate /// action is taken as specified by <see cref="OnOverflow" />. /// </summary> /// <param name="logEventInfo">The log event info.</param> public void Enqueue(AsyncLogEventInfo logEventInfo) { lock (this) { if (logEventInfoQueue.Count >= RequestLimit) { switch (OnOverflow) { case AsyncTargetWrapperOverflowAction.Discard: // dequeue and discard one element logEventInfoQueue.Dequeue(); break; case AsyncTargetWrapperOverflowAction.Grow: break; #if !NET_CF case AsyncTargetWrapperOverflowAction.Block: while (logEventInfoQueue.Count >= RequestLimit) { InternalLogger.Trace("Blocking..."); Monitor.Wait(this); InternalLogger.Trace("Entered critical section."); } InternalLogger.Trace("Limit ok."); break; #endif } } logEventInfoQueue.Enqueue(logEventInfo); } }
/// <summary> /// Renders the logging event message and adds it to the internal ArrayList of log messages. /// </summary> /// <param name="logEvent">The logging event.</param> protected override void Write(AsyncLogEventInfo logEvent) { Write(new[] {logEvent}); }
/// <summary> /// Writes an array of logging events to the log target. By default it iterates on all /// events and passes them to "Write" method. Inheriting classes can use this method to /// optimize batch writes. /// </summary> /// <param name="logEvents">Logging events to be written out.</param> protected virtual void Write(AsyncLogEventInfo[] logEvents) { for (var i = 0; i < logEvents.Length; ++i) { Write(logEvents[i]); } }
/// <summary> /// Forwards the specified log event to all sub-targets. /// </summary> /// <param name="logEvent">The log event.</param> protected override void Write(AsyncLogEventInfo logEvent) { AsyncHelpers.ForEachItemSequentially(Targets, logEvent.Continuation, (t, cont) => t.WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(cont))); }
/// <summary> /// Writes log event to the log target. Must be overridden in inheriting /// classes. /// </summary> /// <param name="logEvent">Log event to be written out.</param> protected virtual void Write(AsyncLogEventInfo logEvent) { try { Write(logEvent.LogEvent); logEvent.Continuation(null); } catch (Exception exception) { if (exception.MustBeRethrown()) { throw; } logEvent.Continuation(exception); } }
/// <summary> /// Writes the specified log event to the wrapped target, retrying and pausing in case of an error. /// </summary> /// <param name="logEvent">The log event.</param> protected override void Write(AsyncLogEventInfo logEvent) { AsyncContinuation continuation = null; var counter = 0; continuation = ex => { if (ex == null) { logEvent.Continuation(null); return; } var retryNumber = Interlocked.Increment(ref counter); InternalLogger.Warn("Error while writing to '{0}': {1}. Try {2}/{3}", WrappedTarget, ex, retryNumber, RetryCount); // exceeded retry count if (retryNumber >= RetryCount) { InternalLogger.Warn("Too many retries. Aborting."); logEvent.Continuation(ex); return; } // sleep and try again Thread.Sleep(RetryDelayMilliseconds); WrappedTarget.WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(continuation)); }; WrappedTarget.WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(continuation)); }
/// <summary> /// Adds the specified log event to the buffer and flushes /// the buffer in case the buffer gets full. /// </summary> /// <param name="logEvent">The log event.</param> protected override void Write(AsyncLogEventInfo logEvent) { WrappedTarget.PrecalculateVolatileLayouts(logEvent.LogEvent); var count = buffer.Append(logEvent); if (count >= BufferSize) { var events = buffer.GetEventsAndClear(); WrappedTarget.WriteAsyncLogEvents(events); } else { if (FlushTimeout > 0) { // reset the timer on first item added to the buffer or whenever SlidingTimeout is set to true if (SlidingTimeout || count == 1) { flushTimer.Change(FlushTimeout, -1); } } } }
/// <summary> /// Prepares an array of parameters to be passed based on the logging event and calls DoInvoke(). /// </summary> /// <param name="logEvent"> /// The logging event. /// </param> protected override void Write(AsyncLogEventInfo logEvent) { var parameters = new object[Parameters.Count]; var i = 0; foreach (var mcp in Parameters) { parameters[i++] = mcp.GetValue(logEvent.LogEvent); } DoInvoke(parameters, logEvent.Continuation); }
/// <summary> /// Forwards the log message to the <see cref="WrapperTargetBase.WrappedTarget" /> by calling the /// <see /// cref="Target.Write(LogEventInfo)" /> /// method <see cref="RepeatCount" /> times. /// </summary> /// <param name="logEvent">The log event.</param> protected override void Write(AsyncLogEventInfo logEvent) { AsyncHelpers.Repeat(RepeatCount, logEvent.Continuation, cont => WrappedTarget.WriteAsyncLogEvent(logEvent.LogEvent.WithContinuation(cont))); }
/// <summary> /// Evaluates all filtering rules to find the first one that matches. /// The matching rule determines the filtering condition to be applied /// to all items in a buffer. If no condition matches, default filter /// is applied to the array of log events. /// </summary> /// <param name="logEvents">Array of log events to be post-filtered.</param> protected override void Write(AsyncLogEventInfo[] logEvents) { ConditionExpression resultFilter = null; InternalLogger.Trace("Running {0} on {1} events", this, logEvents.Length); // evaluate all the rules to get the filtering condition for (var i = 0; i < logEvents.Length; ++i) { foreach (var rule in Rules) { var v = rule.Exists.Evaluate(logEvents[i].LogEvent); if (boxedTrue.Equals(v)) { InternalLogger.Trace("Rule matched: {0}", rule.Exists); resultFilter = rule.Filter; break; } } if (resultFilter != null) { break; } } if (resultFilter == null) { resultFilter = DefaultFilter; } if (resultFilter == null) { WrappedTarget.WriteAsyncLogEvents(logEvents); } else { InternalLogger.Trace("Filter to apply: {0}", resultFilter); // apply the condition to the buffer var resultBuffer = new List<AsyncLogEventInfo>(); for (var i = 0; i < logEvents.Length; ++i) { var v = resultFilter.Evaluate(logEvents[i].LogEvent); if (boxedTrue.Equals(v)) { resultBuffer.Add(logEvents[i]); } else { // anything not passed down will be notified about successful completion logEvents[i].Continuation(null); } } InternalLogger.Trace("After filtering: {0} events.", resultBuffer.Count); if (resultBuffer.Count > 0) { InternalLogger.Trace("Sending to {0}", WrappedTarget); WrappedTarget.WriteAsyncLogEvents(resultBuffer.ToArray()); } } }
/// <summary> /// Writes the specified array of logging events to a file specified in the FileName /// parameter. /// </summary> /// <param name="logEvents"> /// An array of <see cref="LogEventInfo " /> objects. /// </param> /// <remarks> /// This function makes use of the fact that the events are batched by sorting /// the requests by filename. This optimizes the number of open/close calls /// and can help improve performance. /// </remarks> protected override void Write(AsyncLogEventInfo[] logEvents) { var buckets = logEvents.BucketSort(c => FileName.Render(c.LogEvent)); using (var ms = new MemoryStream()) { var pendingContinuations = new List<AsyncContinuation>(); foreach (var bucket in buckets) { var fileName = bucket.Key; ms.SetLength(0); ms.Position = 0; LogEventInfo firstLogEvent = null; foreach (var ev in bucket.Value) { if (firstLogEvent == null) { firstLogEvent = ev.LogEvent; } var bytes = GetBytesToWrite(ev.LogEvent); ms.Write(bytes, 0, bytes.Length); pendingContinuations.Add(ev.Continuation); } FlushCurrentFileWrites(fileName, firstLogEvent, ms, pendingContinuations); } } }
/// <summary> /// Writes the log to the target. /// </summary> /// <param name="logEvent">Log event to write.</param> public void WriteAsyncLogEvent(AsyncLogEventInfo logEvent) { lock (SyncRoot) { if (!IsInitialized) { logEvent.Continuation(null); return; } if (initializeException != null) { logEvent.Continuation(CreateInitException()); return; } var wrappedContinuation = AsyncHelpers.PreventMultipleCalls(logEvent.Continuation); try { Write(logEvent.LogEvent.WithContinuation(wrappedContinuation)); } catch (Exception exception) { if (exception.MustBeRethrown()) { throw; } wrappedContinuation(exception); } } }