Back to skills
SkillHub ClubShip Full StackFull Stack

Logging

Imported from https://github.com/lawless-m/claude-skills.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
6
Hot score
82
Updated
March 20, 2026
Overall rating
C3.7
Composite score
3.7
Best-practice grade
C60.4

Install command

npx @skill-hub/cli install lawless-m-claude-skills-logging

Repository

lawless-m/claude-skills

Skill path: .claude/skills/Logging

Imported from https://github.com/lawless-m/claude-skills.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: lawless-m.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install Logging into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/lawless-m/claude-skills before adding Logging to shared team environments
  • Use Logging for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: Logging
description: UTF-8 file logging with automatic date-based filenames and thread-safe operations for RocsMiddleware services
---

# Logging

## Instructions

When helping users implement logging in RocsMiddleware services, follow these guidelines:

1. **Command-Line Option**: Always include `--log-dir` parameter for specifying log directory path

2. **UTF-8 Encoding**: All log files must use UTF-8 encoding without BOM

3. **Automatic Filename Pattern**: Use `{ProgramName}_YYYY_MM_DD.log` format with automatic date rotation

4. **Directory Path Handling**: Smart detection - if path has no extension or ends with separator, treat as directory and use directory name as base filename

5. **Error Handling**: Include console output before logger initialization since logger may fail. Always check if `_logger` is null in exception handlers.

6. **Log Levels**: Use `LogLevel.Debug` with `--debug` flag, default to `LogLevel.Information`

7. **Thread Safety**: The UTF8Writer uses locking for concurrent writes

8. **Utf8LoggingExtensions.cs**: Copy the reference implementation to project's `Services/` directory - provides UTF8Writer, UTF8LoggerProvider, UTF8Logger, and helper methods

## 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**:
- `Utf8LoggingExtensions.cs` - Complete UTF-8 logger implementation (copy to Services/)

# Standard Logging Pattern

All RocsMiddleware services use a consistent logging approach:

1. **Command-line option**: `--log-dir` parameter specifies the directory path
2. **Automatic filename generation**: `{ProgramName}_YYYY_MM_DD.log`
3. **UTF-8 encoding**: All log files use UTF-8 encoding
4. **Date rotation**: Log files automatically rotate daily based on the date

## Implementation

### Command-Line Option

```csharp
[Option("log-dir", Required = false, HelpText = "Directory for log files")]
public string? LogDir { get; set; }
```

### Logger Initialization

```csharp
// 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

```bash
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 `.log` extension is added automatically
- Date string in format `YYYY_MM_DD` is inserted before the extension

### Examples

| Input `--log-dir`                    | Output Log File                                                    |
|--------------------------------------|---------------------------------------------------------------------|
| `C:\Logs\MyProgram`                  | `C:\Logs\MyProgram\MyProgram_2025_10_16.log`                       |
| `C:\Logs\MyProgram\`                 | `C:\Logs\MyProgram\MyProgram_2025_10_16.log`                       |
| `C:\Logs\MyProgram\custom.log`       | `C:\Logs\MyProgram\custom_2025_10_16.log`                          |
| `C:\Logs\MyProgram\custom`           | `C:\Logs\MyProgram\custom_2025_10_16.log` (adds .log extension)   |

## UTF8LoggingExtensions.cs

All services include a `Services/Utf8LoggingExtensions.cs` file that provides:

- `UTF8Writer` class: Low-level UTF-8 file writer with thread-safe locking
- `UTF8LoggerProvider`: Custom logger provider for Microsoft.Extensions.Logging
- `UTF8Logger`: ILogger implementation that writes to UTF-8 files
- `CreateUtf8Logger()`: Helper method to create a configured logger instance
- `ConfigureUtf8Logging()`: Extension method for ILoggingBuilder

## Error Handling

### Before Logger Initialization

Since the logger may fail to initialize, always include console output for early errors:

```csharp
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:

- `LogLevel.Debug`: Verbose diagnostic information (use `--debug` flag)
- `LogLevel.Information`: General informational messages (default)
- `LogLevel.Warning`: Warning messages for non-critical issues
- `LogLevel.Error`: Error messages for failures

## Real-World Examples

### PriceExtractor
```bash
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
```bash
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

1. **Consistent naming**: All services follow the same `{ProgramName}_YYYY_MM_DD.log` pattern
2. **Automatic rotation**: Daily log files without manual intervention
3. **UTF-8 encoding**: Proper support for international characters
4. **Directory-aware**: Smart handling of directory vs. file paths
5. **Optional logging**: Works without `--log-dir` (console only)
6. **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**:
1. Old version of `Utf8LoggingExtensions.cs` without directory path handling
2. Logger initialization failing silently

**Solution**:
- Copy `Utf8LoggingExtensions.cs` from this skills folder to your project's `Services/` directory
- Add console debug output before logger initialization (see Error Handling section above)
- Check that the `UTF8Writer.Init()` method includes directory detection logic

### Program Exits with "Error" and No Details

**Symptom**: Program outputs just "Error" with no stack trace or details.

**Causes**:
1. Exception thrown before logger is initialized
2. Exception handler trying to use null logger

**Solution**:
- Add console output at key points (see Error Handling section)
- Wrap exception handler to check if `_logger` is null before using it
- Check log file was actually created and contains error details

## Related Files

- `Utf8LoggingExtensions.cs`: Reference implementation included in this folder - copy to your project's `Services/` directory
- Command-line parsing: Uses `CommandLineParser` library
- All services in RocsMiddleware follow this pattern

## Notes

- Log files are created on-demand when the first log message is written
- If `--log-dir` is not specified, logging goes to console only (if enabled)
- 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
Logging | SkillHub