如何使用log4net登录RichTextBox?

Ron*_*nto 3 .net log4net c#-4.0

我想看看Windows.Forms.RichTextBox中显示的log4net条目.我正在考虑使用MemoryAppender,但我不确定每次将其添加为事件时如何获取该条目.

cas*_*One 7

log4net本质上是推送模型,这并不明显(大多数人将方法调用与拉模型相关联),但我们可以将其更改为大多数.NET开发人员更熟悉(事件)的另一个推送模型,并在顶部构建另一个推送模型这使我们更容易订阅/取消订阅这些事件(可观察的).

什么,你需要做的就是创建一个实现IAppender接口,并转换为接口实现到事件的调用.

让我们定义EventArgs您将用于指示事件发生的类:

public class LogEventArgs : EventArgs
{
    public LogEventArgs(IEnumerable<LoggingEvent> loggingEvents)
    {
        // Validate parameters.
        if (loggingEvents == null) 
            throw new ArgumentNullException("loggingEvents");

        // Assign values.
        LoggingEvents = loggingEvents;
    }

    // Poor-man's immutability.
    public IEnumerable<LoggingEvent> LoggingEvents { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

值得注意的是,这是暴露一系列LoggingEvent实例,因为我们也希望支持该IBulkAppender接口.

有了这个,我们可以创建一个实现IAppender.请注意,您只需要实现两种方法.两者中更重要的DoAppend是您将呼叫转换为事件的位置:

public class EventAppender : AppenderSkeleton
{
    // Note, you will probably have to override other things here.

    // The lock for the event.
    private readonly object _eventLock = new object();

    // The backing field for the event.
    private EventHandler<LogEventArgs> _loggedEventHandlers;

    // Add and remove methods.
    public event Logged
    {
        add { lock(_eventLock) _loggedEventHandlers += value; }
        remove { lock(_eventLock) _loggedEventHandlers -= value; }
    }

    // Singular case.
    protected override void Append(LoggingEvent loggingEvent)
    {
        // Validate parameters.
        if (loggingEvent == null) 
            throw new ArgumentNullException("loggingEvent");

        // Call the override that processes these in bulk.
        Append(new [] { loggingEvent });
    }

    // Multiple case.
    protected override void Append(LoggingEvent[] loggingEvents)
    {
        // Validate parameters.
        if (loggingEvents == null)
            throw new ArgumentNullException("loggingEvents");

        // The event handlers.
        EventHandler<LogEventArgs> handlers;

        // Get the handlers.
        lock (_eventLock) handlers = _loggedEventHandlers;

        // Fire if not null.
        if (handlers != null) handlers(new LogEventArgs(loggingEvents);
    }
}
Run Code Online (Sandbox Code Playgroud)

完成后,您可以以编程方式附加appender.以编程方式执行此操作可能更容易,因为它有助于查找将事件附加到的实例.但是,如果这是您的偏好,您可以遍历appender列表以找到它.

然后,只需将事件从此实例连接到将写入的处理程序RichTextBox.

完成后,您可以轻松地将其转换为IObservable<T>实现,并展平所有LoggingEvent实例.

首先,您将使用上面的类,并IObservable<LogEventArgs>使用该Observable.FromEvent方法创建一个:

// The appender that was added programmatically.
EventAppender appender = ...;

// Get the observable of LogEventArgs first.
IObservable<LogEventArgs> logEventObservable = 
    Observable.FromEvent<LogEventArgs>(
        a => appender.Logged += a, a => appender.Logged -= a);
Run Code Online (Sandbox Code Playgroud)

但是,在这一点上,我们希望能够更轻松地处理LoggingEvent类的各个实例.没有理由你的代码必须这样做.使用SelectMany扩展方法可以轻松完成:

// The observable of the individual LoggingEvent instances.
IObservable<LoggingEvent> loggingEvents = logEventObservable.
    SelectMany(e => e.LoggingEvents);
Run Code Online (Sandbox Code Playgroud)

从那里,您可以轻松订阅IObservable<LoggingEvent>实例,以便在新事件进入时发布到UI线程:

// The RichTextBox.
RichTextBox rtb = ...;

// This code goes where you want to start subscribing.  This needs to be
// called on the UI thread, because you need the proper
// SynchronizationContext:
IObservable<LoggingEvent> synchronized = loggingEvents.ObserveOn(
    SynchronizationContext.Current);

// Subscribe to the event.  Store the result of this.
IDisposable unsubscribe = synchronized.
    // If you need to do anything fancier, then use the
    // LoggingEvent represented in e and update the
    // RichTextBox accordingly.
    Subscribe(e => rtb.AppendText(e.RenderedMessage));
Run Code Online (Sandbox Code Playgroud)

然后,如果要取消订阅(停止接收更新),只需调用从调用返回的实现的Dispose方法IDisposable即可Subscribe.

使用IObservable<T>这里的一些优点是:

  • 通过该ObserveOn方法为您处理回调到UI线程的调度.
  • 你可以过滤/转换/等.通过在System.Reactive.Linq命名空间中使用扩展方法来实现序列,特别是允许在C#中使用查询表达式Observable上的扩展方法.
  • 对于扩展IObservable<T>实现允许你做这样的事情的缓冲(如果你要这样一次邮件太多),滑动窗口等.
  • 您可以轻松地将此事件流与其他事件流组合在一起.