Files
nfc-actions/NfcActions/Services/LogService.cs
Amal Graafstra 5b6a7f0fa5 Initial commit: NFC Actions Windows tray application
Implement PC/SC-based NFC card reader monitoring application with WPF UI. Features include:
- System tray integration with single-click to open main window
- Dynamic reader detection and management with enable/disable per reader
- NDEF payload extraction supporting Type 2 and Type 4 tags
- Auto-detection of block sizes (4-byte vs 16-byte) for different reader types
- Configurable actions: copy to clipboard, launch URLs, keyboard input simulation
- URI record type detection - only launches browser for actual URI records
- Real-time activity logging with color-coded levels (Debug, Info, Warning, Error)
- File-based debug logging for troubleshooting
- Settings persistence between sessions
- Dangerous Things branding with custom icons and clickable logo

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-06 22:56:11 -08:00

107 lines
2.8 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
namespace NfcActions.Services;
public class LogService
{
private readonly SynchronizationContext? _syncContext;
private readonly string _logFilePath;
private readonly object _fileLock = new();
public ObservableCollection<LogEntry> LogEntries { get; } = new();
private const int MAX_LOG_ENTRIES = 500;
public LogService()
{
_syncContext = SynchronizationContext.Current;
// Create log file in the same directory as the executable
var exePath = Assembly.GetExecutingAssembly().Location;
var exeDir = Path.GetDirectoryName(exePath) ?? Environment.CurrentDirectory;
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
_logFilePath = Path.Combine(exeDir, $"nfc-actions-debug-{timestamp}.log");
// Write initial header
WriteToFile($"=== NFC Actions Debug Log - Started at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ===");
WriteToFile($"Log file: {_logFilePath}");
WriteToFile("");
}
public void Log(string message, LogLevel level = LogLevel.Info)
{
var entry = new LogEntry
{
Timestamp = DateTime.Now,
Message = message,
Level = level
};
// Write to file immediately
WriteToFile($"[{entry.Timestamp:HH:mm:ss.fff}] [{level}] {message}");
// Update UI
if (_syncContext != null)
{
_syncContext.Post(_ => AddEntry(entry), null);
}
else
{
Application.Current?.Dispatcher.Invoke(() => AddEntry(entry));
}
}
private void WriteToFile(string message)
{
try
{
lock (_fileLock)
{
File.AppendAllText(_logFilePath, message + Environment.NewLine);
}
}
catch
{
// Ignore file write errors
}
}
private void AddEntry(LogEntry entry)
{
LogEntries.Insert(0, entry);
// Keep only the last MAX_LOG_ENTRIES
while (LogEntries.Count > MAX_LOG_ENTRIES)
{
LogEntries.RemoveAt(LogEntries.Count - 1);
}
}
public void Debug(string message) => Log(message, LogLevel.Debug);
public void Info(string message) => Log(message, LogLevel.Info);
public void Warning(string message) => Log(message, LogLevel.Warning);
public void Error(string message) => Log(message, LogLevel.Error);
}
public class LogEntry
{
public DateTime Timestamp { get; set; }
public string Message { get; set; } = string.Empty;
public LogLevel Level { get; set; }
public string FormattedMessage => $"[{Timestamp:HH:mm:ss.fff}] {Message}";
}
public enum LogLevel
{
Debug,
Info,
Warning,
Error
}