Reputation: 21
Help!
I can not figure it out how to implement Serilog to output my logs in real time into a textbox from Winforms. I have an application written in .Net C# that was written a long time ago and had the logging framework log4net. I had different appenders and one was created in my code :
public class ExAppender : AppenderSkeleton{
private IExAppender control = null;
public void AttachControl(IExAppender obj)
{ this.control = obj;}
protected override void Append(LoggingEvent loggingEvent)
{
try
{
string message = RenderLoggingEvent(loggingEvent);
if (this.control != null)
{
this.control.LogMessage(message, loggingEvent.Level.Name);
}
}catch{// ignore}
}
And after that I had another class defined ExLogger:
public static class ExLogger
{ private static readonly ILog LoggerObj = null;
public static bool AttachControl(IExAppender obj)
{
IAppender[] appenders = LoggerObj.Logger.Repository.GetAppenders();
(appender as ExAppender).AttachControl(obj);
return true;
}
return false;}
I defined my serilog loggers in app.config, I want to read them from there because i have multiple loggers, I think that I need to use public class ExAppender : ILogEventSink, I replaced the old code to be suitable for Serilog, it writes to files, to eventLog, console etc, BUT I could not found a way to attach a windows to the logger and to write there. After my modification I obtaind something like this:
public class ExAppender : ILogEventSink
{
public ExAppender control = null;
public ConcurrentQueue<string> Events { get; } = new ConcurrentQueue<string>();
public void AttachControl(IExAppender obj)
{
this.control = obj;
}
public void Emit(LogEvent logEvent)
{
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
var renderSpace = new ExAppender();
Events.Enqueue(renderSpace.ToString());
try
{ string message = logEvent.RenderMessage();
if (this.control != null)
{
this.control.LogMessage(message, logEvent.Level.ToString());
}
}catch { }
}
And for the ExLogger class:
public static bool AttachControl( IExAppender obj)
{try
{
ILogger test = new LoggerConfiguration()
.ReadFrom.AppSettings(settingPrefix: "ExAppender")
.WriteTo.ExAppender(restrictedToMinimumLevel: LogEventLevel.Information)
.CreateLogger();
return true;
}catch
{
return false;
}}
Can someone guide me? Does someone has an example or maybe explain what am I missing?
Upvotes: 2
Views: 3109
Reputation: 695
Maybe I am a bit too late to help you, but this is how I implemented it:
Custom logger sink, which has EventHandler:
public class TbsLoggerSink : ILogEventSink
{
public event EventHandler NewLogHandler;
public TbsLoggerSink() { }
public void Emit(LogEvent logEvent)
{
#if DEBUG
Console.WriteLine($"{logEvent.Timestamp}] {logEvent.MessageTemplate}");
#endif
NewLogHandler?.Invoke(typeof(TbsCore.Helpers.TbsLoggerSink), new LogEventArgs() { Log = logEvent });
}
}
public class LogEventArgs : EventArgs
{
public LogEvent Log { get; set; }
}
When creating the Serilog logger, add your custom sink. I use static sink/logger so I can access it from anywhere.
public static TbsLoggerSink LoggerSink = new TbsLoggerSink();
public static readonly Serilog.Core.Logger Log = new LoggerConfiguration()
.WriteTo.Sink(LoggerSink)
.CreateLogger();
Than in your view/form, where you have TextBox/RichTextBox (in my case this.logTextBox), add event handler:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
Utils.LoggerSink.NewLogHandler += LogHandler;
}
private void LogHandler(object sender, EventArgs e)
{
var log = ((LogEventArgs)e).Log;
this.logTextBox.Text = $"{log.Timestamp.DateTime.ToString("HH:mm:ss")}: {log.MessageTemplate}\n{this.logTextBox.Text}";
}
}
Upvotes: 2