Configurando log4net TextBoxAppender (appender personalizado) a través de un archivo Xml

Esto es una continuación de mi pregunta: Interfaz de registro flexible …

Ahora quiero escribir un apéndice de log4net personalizado para un TextBox de varias líneas, para mi aplicación WinForms 2.0. Uno de los miembros de StackOverflow devdigital ya me ha señalado este enlace:

TextBox Appender

Sin embargo, el artículo no describe cómo configurar dicho appender a través de un archivo Xml. El problema único al configurar este appender es que necesitamos pasar una referencia a un objeto TextBox a este appender.

Entonces, ¿es posible configurarlo usando un archivo Xml? ¿O pueden los anexos solo configurarse mediante progtwigción? ¿Cuáles son las opciones para hacer que sea tan configurable o lo más parecida posible, puede estar utilizando una combinación de archivo Xml y código?

Gracias.

Depende de la forma en que configure log4net, pero normalmente no se crearán formularios (y, por lo tanto, cuadros de texto) cuando log4net lea la configuración. Por lo tanto, debe crear propiedades para los nombres de formulario y de cuadro de texto. Y debe verificar si el formulario está abierto y si ha proporcionado el cuadro de texto justo antes de agregar el evento de registro. También es mejor heredar de AppenderSkeleton que implementar IAppender desde cero:

 public class TextBoxAppender : AppenderSkeleton { private TextBox _textBox; public string FormName { get; set; } public string TextBoxName { get; set; } protected override void Append(LoggingEvent loggingEvent) { if (_textBox == null) { if (String.IsNullOrEmpty(FormName) || String.IsNullOrEmpty(TextBoxName)) return; Form form = Application.OpenForms[FormName]; if (form == null) return; _textBox = form.Controls[TextBoxName] as TextBox; if (_textBox == null) return; form.FormClosing += (s, e) => _textBox = null; } _textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine); } } 

La configuración es simple (log4net leerá los elementos xml y proporcionará valores para las propiedades con los mismos nombres):

            

No proporcioné ningún código o código de manejo de errores relacionado con la sincronización de subprocesos múltiples y subprocesos, porque la pregunta es acerca de la configuración de los apéndices.

aquí hay una versión actualizada de todos los comentarios superiores: hilo seguro, no bloquea la aplicación y utiliza el patrón de conversión:

 namespace MyNamespace { public class TextBoxAppender : AppenderSkeleton { private TextBox _textBox; public TextBox AppenderTextBox { get { return _textBox; } set { _textBox = value; } } public string FormName { get; set; } public string TextBoxName { get; set; } private Control FindControlRecursive(Control root, string textBoxName) { if (root.Name == textBoxName) return root; foreach (Control c in root.Controls) { Control t = FindControlRecursive(c, textBoxName); if (t != null) return t; } return null; } protected override void Append(log4net.Core.LoggingEvent loggingEvent) { if (_textBox == null) { if (String.IsNullOrEmpty(FormName) || String.IsNullOrEmpty(TextBoxName)) return; Form form = Application.OpenForms[FormName]; if (form == null) return; _textBox = (TextBox)FindControlRecursive(form, TextBoxName); if (_textBox == null) return; form.FormClosing += (s, e) => _textBox = null; } _textBox.BeginInvoke((MethodInvoker)delegate { _textBox.AppendText(RenderLoggingEvent(loggingEvent)); }); } } } 

La configuración, coloca esto en app.config:

             

Modifiqué el appender para trabajar con multihilo. Además, adjunté la configuración del código.

Saludos, Dorin

Appender:

 public class TextBoxAppender : AppenderSkeleton { private TextBox _textBox; public TextBox AppenderTextBox { get { return _textBox; } set { _textBox = value; } } public string FormName { get; set; } public string TextBoxName { get; set; } private Control FindControlRecursive(Control root, string textBoxName) { if (root.Name == textBoxName) return root; foreach (Control c in root.Controls) { Control t = FindControlRecursive(c, textBoxName); if (t != null) return t; } return null; } protected override void Append(log4net.Core.LoggingEvent loggingEvent) { if (_textBox == null) { if (String.IsNullOrEmpty(FormName) || String.IsNullOrEmpty(TextBoxName)) return; Form form = Application.OpenForms[FormName]; if (form == null) return; _textBox = (TextBox)FindControlRecursive(form, TextBoxName); if (_textBox == null) return; form.FormClosing += (s, e) => _textBox = null; } _textBox.Invoke((MethodInvoker)delegate { _textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine); }); } } 

Configuración:

  var textBoxAppender = new Util.TextBoxAppender(); textBoxAppender.TextBoxName = "textLog"; textBoxAppender.FormName = "MainTarget"; textBoxAppender.Threshold = log4net.Core.Level.All; var consoleAppender = new log4net.Appender.ConsoleAppender { Layout = new log4net.Layout.SimpleLayout() }; var list = new AppenderSkeleton[] { textBoxAppender, consoleAppender }; log4net.Config.BasicConfigurator.Configure(list); 

La línea real que se agrega al cuadro de texto debe ser …

 _textBox.AppendText(RenderLoggingEvent(loggingEvent)); 

… si desea aprovechar un diseño de patrón. De lo contrario, simplemente envía el texto del mensaje (el diseño predeterminado).

La muestra de arriba de Klodoma es bastante buena. Si cambia el cuadro de texto a richtextbox, puede hacer más con el resultado. Aquí hay un código para colorear los mensajes de código por nivel:

  System.Drawing.Color text_color; switch (loggingEvent.Level.DisplayName.ToUpper()) { case "FATAL": text_color = System.Drawing.Color.DarkRed; break; case "ERROR": text_color = System.Drawing.Color.Red; break; case "WARN": text_color = System.Drawing.Color.DarkOrange; break; case "INFO": text_color = System.Drawing.Color.Teal; break; case "DEBUG": text_color = System.Drawing.Color.Green; break; default: text_color = System.Drawing.Color.Black; break; } _TextBox.BeginInvoke((MethodInvoker)delegate { _TextBox.SelectionColor = text_color; _TextBox.AppendText(RenderLoggingEvent(loggingEvent)); }); 

Si realmente quieres, los colores se pueden mapear desde la configuración de log4net de la misma manera que el ColorConsoleAppender, pero lo dejo para que el siguiente codificador tropiece con esta muestra …

Preferiría el siguiente enfoque si desea realizar el registro en varios lugares de su aplicación. Este enfoque ofrece la flexibilidad de cambiar dinámicamente la instancia de control a través del código.

TextBoxAppender

 public class TextBoxAppender : AppenderSkeleton { public RichTextBox RichTextBox { get; set; } protected override void Append(LoggingEvent loggingEvent) { Action operation = () => { this.RichTextBox.AppendText(RenderLoggingEvent(loggingEvent)); }; this.RichTextBox.Invoke(operation); } } 

El código para asignar la instancia del cuadro de texto. Haga esto antes de comenzar el proceso que realiza el registro.

  var appender = LogManager.GetRepository().GetAppenders().Where(a => a.Name == "TextBoxAppender").FirstOrDefault(); if (appender != null) ((TextBoxAppender)appender).RichTextBox = this.richTextBoxLog; 

La configuración