Claude-skill-registry Logging
UTF-8 file logging with automatic date-based filenames and thread-safe operations for RocsMiddleware services
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/logging" ~/.claude/skills/majiayu000-claude-skill-registry-logging-aa802c && rm -rf "$T"
skills/data/logging/SKILL.mdLogging
Instructions
When helping users implement logging in RocsMiddleware services, follow these guidelines:
-
Command-Line Option: Always include
parameter for specifying log directory path--log-dir -
UTF-8 Encoding: All log files must use UTF-8 encoding without BOM
-
Automatic Filename Pattern: Use
format with automatic date rotation{ProgramName}_YYYY_MM_DD.log -
Directory Path Handling: Smart detection - if path has no extension or ends with separator, treat as directory and use directory name as base filename
-
Error Handling: Include console output before logger initialization since logger may fail. Always check if
is null in exception handlers._logger -
Log Levels: Use
withLogLevel.Debug
flag, default to--debugLogLevel.Information -
Thread Safety: The UTF8Writer uses locking for concurrent writes
-
Utf8LoggingExtensions.cs: Copy the reference implementation to project's
directory - provides UTF8Writer, UTF8LoggerProvider, UTF8Logger, and helper methodsServices/
Examples
Example 1: Basic Logger Setup
User: Help me add logging to my RocsMiddleware service Claude: I'll set up the standard UTF-8 file logging pattern: - Add --log-dir command-line option - Copy Utf8LoggingExtensions.cs to Services/ - Initialize logger with automatic date-based filename - Add console output before logger initialization for debugging [Provides implementation using the Logger Initialization pattern from reference material below]
Example 2: Directory Path Handling
User: Why isn't my log file being created when I specify --log-dir? Claude: Let me check the directory path handling. The logger should: - Detect if path is a directory (no extension or ends with separator) - Use directory name as base filename - Add date string and .log extension automatically Common issue: Old Utf8LoggingExtensions.cs without directory detection logic. Solution: Copy the updated version from skills folder. [Provides directory detection implementation from reference material below]
Example 3: Error Handling Before Logger Init
User: My program just prints "Error" with no details Claude: This happens when an exception occurs before logger initialization. I'll add: - Console.WriteLine at key points (startup, before logger init, after logger init) - Null check on _logger in exception handler - Fallback to console output if logger is null [Provides error handling pattern from reference material below]
Reference Implementation Details
The sections below contain proven working code from RocsMiddleware services that the examples above reference.
Reference Files in This Folder:
- Complete UTF-8 logger implementation (copy to Services/)Utf8LoggingExtensions.cs
Standard Logging Pattern
All RocsMiddleware services use a consistent logging approach:
- Command-line option:
parameter specifies the directory path--log-dir - Automatic filename generation:
{ProgramName}_YYYY_MM_DD.log - UTF-8 encoding: All log files use UTF-8 encoding
- Date rotation: Log files automatically rotate daily based on the date
Implementation
Command-Line Option
[Option("log-dir", Required = false, HelpText = "Directory for log files")] public string? LogDir { get; set; }
Logger Initialization
// Initialize logger with optional log directory var logLevel = options.Debug ? LogLevel.Debug : LogLevel.Information; _logger = {Namespace}.Services.Utf8LoggingExtensions.CreateUtf8Logger( "{ProgramName}", logLevel, options.LogDir);
Example Usage
dotnet run -- --log-dir "C:\RI Services\Logs\MyProgram" --other-options
This creates:
C:\RI Services\Logs\MyProgram\MyProgram_2025_10_16.log
Directory Path Handling
The
UTF8Writer.Init() method automatically detects directory paths and creates properly named log files:
- If path has no extension and ends with a path separator (or exists as a directory), it's treated as a directory
- The directory name becomes the base name for the log file
- Default
extension is added automatically.log - Date string in format
is inserted before the extensionYYYY_MM_DD
Examples
Input | Output Log File |
|---|---|
| |
| |
| |
| (adds .log extension) |
UTF8LoggingExtensions.cs
All services include a
Services/Utf8LoggingExtensions.cs file that provides:
class: Low-level UTF-8 file writer with thread-safe lockingUTF8Writer
: Custom logger provider for Microsoft.Extensions.LoggingUTF8LoggerProvider
: ILogger implementation that writes to UTF-8 filesUTF8Logger
: Helper method to create a configured logger instanceCreateUtf8Logger()
: Extension method for ILoggingBuilderConfigureUtf8Logging()
Error Handling
Before Logger Initialization
Since the logger may fail to initialize, always include console output for early errors:
public static async Task Main(string[] args) { try { Console.WriteLine("{ProgramName} starting..."); // Parse command line CommandLineOptions? options = null; Parser.Default.ParseArguments<CommandLineOptions>(args) .WithParsed(opts => options = opts) .WithNotParsed(errors => { Console.WriteLine("Failed to parse command line arguments"); Environment.Exit(1); }); if (options == null) { Console.WriteLine("Failed to parse command line options"); Environment.Exit(1); return; } Console.WriteLine($"Initializing logger with log-dir: {options.LogDir ?? "(null)"}"); // Initialize logger _logger = {Namespace}.Services.Utf8LoggingExtensions.CreateUtf8Logger( "{ProgramName}", options.Debug ? LogLevel.Debug : LogLevel.Information, options.LogDir); Console.WriteLine("Logger initialized"); _logger.LogInformation("{ProgramName} starting"); // ... rest of program } catch (Exception ex) { if (_logger != null) { _logger.LogError(ex, "{ProgramName} failed: {Message}", ex.Message); } else { Console.WriteLine($"{ProgramName} failed: {ex.Message}"); Console.WriteLine(ex.StackTrace); } Environment.Exit(1); } }
Log Levels
Standard log levels used across all services:
: Verbose diagnostic information (useLogLevel.Debug
flag)--debug
: General informational messages (default)LogLevel.Information
: Warning messages for non-critical issuesLogLevel.Warning
: Error messages for failuresLogLevel.Error
Real-World Examples
PriceExtractor
dotnet run -- --pqdir "R:\Outputs\Parquets\poller" --pg "R:\JsonParams\x3rocs_db.json" --log-dir "C:\RI Services\Logs\PriceExtractor" --full
Creates:
C:\RI Services\Logs\PriceExtractor\PriceExtractor_2025_10_16.log
PriceDiscountUploader
dotnet run -- --pg "R:/JsonParams/x3rocs_db.json" --log-dir "R:/Logs/PriceDiscounter" --elastic https://rocs-stage-es.ramsden-international.com/ --debug --sphkey1 425073
Creates:
R:/Logs/PriceDiscounter/PriceDiscounter_2025_10_16.log
Benefits
- Consistent naming: All services follow the same
pattern{ProgramName}_YYYY_MM_DD.log - Automatic rotation: Daily log files without manual intervention
- UTF-8 encoding: Proper support for international characters
- Directory-aware: Smart handling of directory vs. file paths
- Optional logging: Works without
(console only)--log-dir - Thread-safe: Multiple threads can log simultaneously
Common Issues
No Log File Created
Symptom: Program runs but no log file appears in the specified directory.
Causes:
- Old version of
without directory path handlingUtf8LoggingExtensions.cs - Logger initialization failing silently
Solution:
- Copy
from this skills folder to your project'sUtf8LoggingExtensions.cs
directoryServices/ - Add console debug output before logger initialization (see Error Handling section above)
- Check that the
method includes directory detection logicUTF8Writer.Init()
Program Exits with "Error" and No Details
Symptom: Program outputs just "Error" with no stack trace or details.
Causes:
- Exception thrown before logger is initialized
- Exception handler trying to use null logger
Solution:
- Add console output at key points (see Error Handling section)
- Wrap exception handler to check if
is null before using it_logger - Check log file was actually created and contains error details
Related Files
: Reference implementation included in this folder - copy to your project'sUtf8LoggingExtensions.cs
directoryServices/- Command-line parsing: Uses
libraryCommandLineParser - All services in RocsMiddleware follow this pattern
Notes
- Log files are created on-demand when the first log message is written
- If
is not specified, logging goes to console only (if enabled)--log-dir - Parent directories are created automatically if they don't exist
- Log files are UTF-8 encoded without BOM
- The logger uses Microsoft.Extensions.Logging interfaces for compatibility