示例#1
0
        /// <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;
            }
        }
示例#5
0
        /// <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);
            }
        }
示例#6
0
        /// <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;
            }
        }
示例#8
0
        /// <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));
        }
示例#10
0
        /// <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();
                }
            }
        }
示例#11
0
 /// <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);
 }
示例#12
0
        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)));
 }
示例#15
0
        /// <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);
                    }
                }
            }
        }
示例#16
0
 /// <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);
     }
 }
示例#17
0
        /// <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);
            }
        }
示例#18
0
 /// <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});
 }
示例#19
0
 /// <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]);
     }
 }
示例#20
0
 /// <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)));
 }
示例#21
0
        /// <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());
                }
            }
        }
示例#27
0
        /// <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);
                }
            }
        }
示例#28
0
        /// <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);
                }
            }
        }