Bring back C# sample logging!

This commit is contained in:
Caelan Sayler
2025-03-12 22:02:47 +00:00
committed by Caelan
parent 4f10c94565
commit a6337c5a22
7 changed files with 113 additions and 25 deletions

View File

@@ -4,6 +4,7 @@ using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Velopack;
using Velopack.Logging;
namespace CSharpAvalonia;
@@ -19,6 +20,8 @@ public partial class MainWindow : Window
var updateUrl = SampleHelper.GetReleasesDir(); // replace with your update path/url
_um = new UpdateManager(updateUrl);
TextLog.Text = Program.Log.ToString();
Program.Log.LogUpdated += LogUpdated;
UpdateStatus();
}
@@ -29,7 +32,7 @@ public partial class MainWindow : Window
// ConfigureAwait(true) so that UpdateStatus() is called on the UI thread
_update = await _um.CheckForUpdatesAsync().ConfigureAwait(true);
} catch (Exception ex) {
LogMessage("Error checking for updates", ex);
Program.Log.LogError(ex, "Error checking for updates");
}
UpdateStatus();
@@ -42,7 +45,7 @@ public partial class MainWindow : Window
// ConfigureAwait(true) so that UpdateStatus() is called on the UI thread
await _um.DownloadUpdatesAsync(_update, Progress).ConfigureAwait(true);
} catch (Exception ex) {
LogMessage("Error downloading updates", ex);
Program.Log.LogError(ex, "Error downloading updates");
}
UpdateStatus();
@@ -53,16 +56,12 @@ public partial class MainWindow : Window
_um.ApplyUpdatesAndRestart(_update);
}
private void LogMessage(string text, Exception e = null)
private void LogUpdated(object sender, LogUpdatedEventArgs e)
{
// logs can be sent from other threads
Dispatcher.UIThread.InvokeAsync(
() => {
TextLog.Text += text + Environment.NewLine;
if (e != null) {
TextLog.Text += e.ToString() + Environment.NewLine;
}
TextLog.Text = e.Text;
ScrollLog.ScrollToEnd();
});
}
@@ -78,7 +77,7 @@ public partial class MainWindow : Window
private void Working()
{
LogMessage("");
Program.Log.LogInformation("");
BtnCheckUpdate.IsEnabled = false;
BtnDownloadUpdate.IsEnabled = false;
BtnRestartApply.IsEnabled = false;

View File

@@ -0,0 +1,39 @@
using System;
using System.Text;
using Velopack.Logging;
namespace CSharpAvalonia;
public class LogUpdatedEventArgs : EventArgs
{
public string Text { get; set; }
}
public class MemoryLogger : IVelopackLogger
{
public event EventHandler<LogUpdatedEventArgs> LogUpdated;
private readonly StringBuilder _sb = new StringBuilder();
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public override string ToString()
{
lock (_sb) {
return _sb.ToString();
}
}
public void Log(VelopackLogLevel logLevel, string message, Exception exception)
{
lock (_sb) {
message = $"{logLevel}: {message}";
if (exception != null) message += "\n" + exception.ToString();
Console.WriteLine("log: " + message);
_sb.AppendLine(message);
LogUpdated?.Invoke(this, new LogUpdatedEventArgs { Text = _sb.ToString() });
}
}
}

View File

@@ -6,6 +6,8 @@ namespace CSharpAvalonia;
class Program
{
public static MemoryLogger Log { get; private set; } = new();
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
@@ -16,6 +18,7 @@ class Program
// It's important to Run() the VelopackApp as early as possible in app startup.
VelopackApp.Build()
.OnFirstRun((v) => { /* Your first run code here */ })
.SetLogger(Log)
.Run();
// Now it's time to run Avalonia

View File

@@ -5,6 +5,8 @@ namespace CSharpWpf
{
public partial class App : Application
{
public static MemoryLogger Log { get; private set; } = new();
// Since WPF has an "automatic" Program.Main, we need to create our own.
// In order for this to work, you must also add the following to your .csproj:
// <StartupObject>CSharpWpf.App</StartupObject>
@@ -15,6 +17,7 @@ namespace CSharpWpf
// It's important to Run() the VelopackApp as early as possible in app startup.
VelopackApp.Build()
.OnFirstRun((v) => { /* Your first run code here */ })
.SetLogger(Log)
.Run();
// We can now launch the WPF application as normal.

View File

@@ -1,6 +1,7 @@
using System.Text;
using System.Windows;
using Velopack;
using Velopack.Logging;
namespace CSharpWpf
{
@@ -16,6 +17,8 @@ namespace CSharpWpf
string updateUrl = SampleHelper.GetReleasesDir(); // replace with your update url
_um = new UpdateManager(updateUrl);
TextLog.Text = App.Log.ToString();
App.Log.LogUpdated += LogUpdated;
UpdateStatus();
}
@@ -26,7 +29,7 @@ namespace CSharpWpf
// ConfigureAwait(true) so that UpdateStatus() is called on the UI thread
_update = await _um.CheckForUpdatesAsync().ConfigureAwait(true);
} catch (Exception ex) {
LogMessage("Error checking for updates", ex);
App.Log.LogError(ex, "Error checking for updates");
}
UpdateStatus();
}
@@ -38,7 +41,7 @@ namespace CSharpWpf
// ConfigureAwait(true) so that UpdateStatus() is called on the UI thread
await _um.DownloadUpdatesAsync(_update, Progress).ConfigureAwait(true);
} catch (Exception ex) {
LogMessage("Error downloading updates", ex);
App.Log.LogError(ex, "Error downloading updates");
}
UpdateStatus();
}
@@ -48,14 +51,11 @@ namespace CSharpWpf
_um.ApplyUpdatesAndRestart(_update);
}
private void LogMessage(string text, Exception e = null)
private void LogUpdated(object sender, LogUpdatedEventArgs e)
{
// logs can be sent from other threads
this.Dispatcher.InvokeAsync(() => {
TextLog.Text += text + Environment.NewLine;
if (e != null) {
TextLog.Text += e.ToString() + Environment.NewLine;
}
TextLog.Text = e.Text;
ScrollLog.ScrollToEnd();
});
}
@@ -70,7 +70,7 @@ namespace CSharpWpf
private void Working()
{
LogMessage("");
App.Log.LogInformation("");
BtnCheckUpdate.IsEnabled = false;
BtnDownloadUpdate.IsEnabled = false;
BtnRestartApply.IsEnabled = false;

View File

@@ -0,0 +1,39 @@
using System;
using System.Text;
using Velopack.Logging;
namespace CSharpWpf;
public class LogUpdatedEventArgs : EventArgs
{
public string Text { get; set; }
}
public class MemoryLogger : IVelopackLogger
{
public event EventHandler<LogUpdatedEventArgs> LogUpdated;
private readonly StringBuilder _sb = new StringBuilder();
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public override string ToString()
{
lock (_sb) {
return _sb.ToString();
}
}
public void Log(VelopackLogLevel logLevel, string message, Exception exception)
{
lock (_sb) {
message = $"{logLevel}: {message}";
if (exception != null) message += "\n" + exception.ToString();
Console.WriteLine("log: " + message);
_sb.AppendLine(message);
LogUpdated?.Invoke(this, new LogUpdatedEventArgs { Text = _sb.ToString() });
}
}
}