Here is my example of log4net.

First console example

Start new console app

Install package log4net

Add XML file, name it like "log4netConfiguration.xml" and in properties set "Copy to Output Directory" to "Copy always":

<?xml version="1.0" encoding="utf-8" ?> 
<log4net>
    <appender name="myConsoleAppender" type="log4net.Appender.ConsoleAppender">
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
        </layout>
    </appender>
    
    <root>
        <level value="DEBUG" />
        <appender-ref ref="myConsoleAppender" />
    </root>
</log4net>

Here notice the name of appender: myConsoleAppender

Code:

using log4net;
using log4net.Repository;
using System.Reflection;

if (!File.Exists("log4netConfiguration.xml"))
    throw new Exception("File log4netConfiguration.xml does not exist");

ILoggerRepository loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
log4net.Config.XmlConfigurator.Configure(loggerRepository, new FileInfo("log4netConfiguration.xml"));
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
log.Debug("test");
Example download from here

Second console and file example

Just change XML to:

<?xml version="1.0" encoding="utf-8" ?> 
<log4net>
    <appender name="myConsoleAppender" type="log4net.Appender.ConsoleAppender">
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
        </layout>
    </appender>
	
	<appender name="myRollingFileAppender" type="log4net.Appender.RollingFileAppender">
		<file value="example.log" />
		<appendToFile value="true" />
		<maximumFileSize value="100KB" />
		<maxSizeRollBackups value="2" />
 
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%level %thread %logger - %message%newline" />
		</layout>
	</appender>	
    
    <root>
        <level value="DEBUG" />
        <appender-ref ref="myConsoleAppender" />
        <appender-ref ref="myRollingFileAppender" />
    </root>
</log4net>
Notice myRollingFileAppender.

Third WinForms and TextBox example

This example I took from here

XML configuration:

<?xml version="1.0" encoding="utf-8" ?>
<log4net>

	<appender name="myTextBoxAppender" type="log4netWinFormsExample.TextBoxAppender, log4netWinFormsExample">
		<formName value="Form1"/>
		<textBoxName value="textBox1"/>
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%date %-5level %logger - %message" />
		</layout>
	</appender>

	<root>
		<level value="DEBUG" />
		<appender-ref ref="myTextBoxAppender" />
	</root>
</log4net>
Here notice that I have added namespace "log4netWinFormsExample" in the type attribute of appender node:

<appender name="myTextBoxAppender" type="log4netWinFormsExample.TextBoxAppender, log4netWinFormsExample">
TextBoxAppender class:
using log4net.Appender;

namespace log4netWinFormsExample;

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);
        });
    }
}
Here notice line:
_textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine);
Instead you could write:
_textBox.AppendText(RenderLoggingEvent(loggingEvent));
To take advantage of a pattern layout as described in this comment.

The main code:

using System.Reflection;
using log4net;
using log4net.Repository;

namespace log4netWinFormsExample;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void btnLogIt_Click(object sender, EventArgs e)
    {
        if (!File.Exists("log4netConfiguration.xml"))
            throw new Exception("File log4netConfiguration.xml does not exist");

        ILoggerRepository loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
        log4net.Config.XmlConfigurator.Configure(loggerRepository, new FileInfo("log4netConfiguration.xml"));
        var log = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType);
        log.Debug("test");
    }
}
Example download from here