Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

LogWrap

GitHub releaseGitHub DownloadsCoverage BadgelintercoverageSnapshot BuildRelease BuildGoDocLicense

LogWrap is a command execution wrapper that adds configurable prefixes to log output streams. It intercepts stdout and stderr from executed commands and processes them in real-time with customizable formatting including timestamps, log levels, colors, user information, and process IDs.

Features

  • Real-time processing: No buffering delays, immediate output
  • Configurable prefixes: Timestamps, log levels, colors, user info, PID
  • Stream separation: Distinguish between stdout (INFO) and stderr (ERROR)
  • Flexible configuration: YAML config files + CLI flag overrides
  • Log level detection: Automatic detection based on keywords
  • Color support: ANSI color codes for enhanced readability (disabled by default)
  • Signal handling: Clean shutdown and process management
  • Multiple output formats: Text, JSON, structured (planned)

Installation

From Source

git clone https://github.com/sgaunet/logwrap.git
cd logwrap
task build
# Binary will be in ./bin/logwrap

Using Go Install

go install github.com/sgaunet/logwrap/cmd/logwrap@latest

Quick Start

# Basic usage
logwrap echo"Hello World"# With mixed output
logwrap sh -c "echo 'stdout'; echo 'stderr' >&2"# Using configuration file
logwrap -config examples/basic.yaml make build
# Custom template (timestamp only)
logwrap -template "[{{.Timestamp}}] " ls -la
# Enable colors and UTC time
logwrap -colors -utc make test

Usage

logwrap [options] -- <command> [args...]
logwrap [options] <command> [args...]
Options:
-config string Configuration file path
-template string Log prefix template (default "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] ")
-utc Use UTC timestamps (default false)
-colors Enable colored output (default false)
-format string Output format: text, json, structured (default "text")
-help Show help message
-version Show version information
Note: To control user/PID inclusion, either:
- Use -template flag to customize the prefix format
- Edit the config file to set user.enabled or pid.enabled to false

Configuration

LogWrap looks for configuration files in the following order:

  1. File specified with -config flag
  2. ./logwrap.yaml or ./logwrap.yml
  3. ~/.config/logwrap/config.yaml
  4. ~/.logwrap.yaml

Basic Configuration

prefix:
template: "[{{.Timestamp}}] [{{.Level}}] [{{.User}}:{{.PID}}] "timestamp:
# Uses strftime format (Linux date command style)# Common: %Y=year %m=month %d=day %H=hour %M=minute %S=secondformat: "%Y-%m-%d %H:%M:%S"utc: falsecolors:
enabled: falseinfo: "green"error: "red"timestamp: "blue"user:
enabled: true # Control user inclusion in templateformat: "username"# username, uid, or fullpid:
enabled: true # Control PID inclusion in templateformat: "decimal"# decimal or hexoutput:
format: "text"# text, json, or structuredbuffer: "line"# line, none, or fulllog_level:
default_stdout: "INFO"default_stderr: "ERROR"detection:
enabled: truekeywords:
error: ["ERROR", "FATAL", "PANIC"]warn: ["WARN", "WARNING"]debug: ["DEBUG", "TRACE"]info: ["INFO"]

Template Variables

  • {{.Timestamp}} - Formatted timestamp (using strftime format from config)
  • {{.Level}} - Log level (INFO, ERROR, WARN, DEBUG)
  • {{.User}} - User information (controlled by user.enabled and user.format in config)
  • {{.PID}} - Process ID (controlled by pid.enabled and pid.format in config)

Timestamp Format

LogWrap uses strftime format (Linux date command style), not Go's time format:

DirectiveMeaningExample
%Y4-digit year2024
%mMonth (01-12)01
%dDay (01-31)15
%HHour 24h (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45
%zTimezone offset-0700
%fMicroseconds123456
%aWeekday shortMon
%bMonth shortJan

Examples:

  • %Y-%m-%d %H:%M:%S2024-01-15 14:30:45
  • %Y-%m-%dT%H:%M:%S%z2024-01-15T14:30:45-0700
  • %d/%b/%Y %H:%M15/Jan/2024 14:30

Color Options

Available colors: black, red, green, yellow, blue, magenta, cyan, white, none

Log Level Detection

LogWrap automatically detects log levels based on configurable keywords:

  • ERROR: Lines containing "ERROR", "FATAL", "PANIC"
  • WARN: Lines containing "WARN", "WARNING"
  • DEBUG: Lines containing "DEBUG", "TRACE"
  • INFO: Lines containing "INFO" or default for stdout

Configuration Validation

LogWrap validates all configuration before running. Invalid values produce descriptive errors listing the accepted options.

What gets validated:

FieldValid ValuesNotes
Output formattext, json, structured
Log levelsTRACE, DEBUG, INFO, WARN, ERROR, FATALUppercase or lowercase only, no mixed case
Colorsblack, red, green, yellow, blue, magenta, cyan, white, noneCase-insensitive
User formatusername, uid, full
PID formatdecimal, hex
Timestamp formatAny valid strftime stringValidated by round-trip format/parse
Config file path.yaml or .yml extensionPath traversal (..) is rejected

Keyword rules:

  • Each keyword map key must be a valid log level
  • Empty keyword arrays are rejected — if a level is listed, it must have at least one keyword
  • Empty strings in keyword arrays are rejected
  • Keywords cannot be provided when detection is disabled

Examples

Basic Usage

# Simple command
logwrap echo"Hello World"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Hello World# Command with errors
logwrap sh -c "echo 'Success'; echo 'ERROR: Failed' >&2"# Output: [2024-01-15 10:30:45] [INFO] [user:1234] Success# [2024-01-15 10:30:45] [ERROR] [user:1234] ERROR: Failed

Using Configuration Files

# Minimal configuration (timestamp only)
logwrap -config examples/minimal.yaml echo"Simple"# Output: [10:30:45] Simple# Advanced configuration with UTC and hex PID
logwrap -config examples/advanced.yaml echo"Advanced"# Output: [2024-01-15T10:30:45.123456+0000] [INFO] [user(1000):0x4d2] Advanced

Custom Templates

# Timestamp only (no user/PID)
logwrap -template "[{{.Timestamp}}] "echo"Custom"# Output: [2024-01-15 10:30:45] Custom# Level and timestamp only
logwrap -template "{{.Level}}: {{.Timestamp}} - "echo"Level first"# Output: INFO: 2024-01-15 10:30:45 - Level first# Include user but not PID
logwrap -template "[{{.Level}}] [{{.User}}] "echo"No PID"# Output: [INFO] [john] No PID

Long-running Commands

# Monitor a build process
logwrap make build
# Watch log files
logwrap tail -f /var/log/app.log
# Stream processing
logwrap ping google.com

Configuration Examples

See the examples/ directory for:

  • basic.yaml - Standard configuration with all features
  • minimal.yaml - Minimal setup with just timestamps
  • advanced.yaml - Advanced setup with UTC times and extended keywords
  • public-safe.yaml - Privacy-safe configuration for public/shared environments
  • test_commands.sh - Script with various test commands

Architecture

LogWrap is built with a modular architecture:

  • Config Package: YAML configuration and CLI flag handling
  • Executor Package: Command execution with stream capture
  • Processor Package: Real-time stream processing
  • Formatter Package: Log formatting and prefix generation with strftime support

Key Dependencies

  • github.com/itchyny/timefmt-go - Pure Go strftime implementation
    • Provides Linux date command compatible timestamp formatting
    • Efficient and standards-compliant

For detailed architecture information, see docs/ARCHITECTURE.md.

Development

Requirements

  • Go 1.21 or later
  • Task (task runner)

Building and Testing

# Build the binary
task build
# Run all tests
task test# Run tests with coverage
task test-coverage
# Run tests with race detection
task test-race
# Run linter
task linter
# Create snapshot build
task snapshot

For more development commands, see CLAUDE.md.

Security Considerations

Important: LogWrap is a logging wrapper, not a security sandbox. It does not provide isolation or restrict the commands it executes.

Security Model

What LogWrap protects against:

  • Path traversal: Commands containing .. in paths are rejected

What LogWrap does NOT protect against:

  • Command injection: Arguments are passed directly to the executed command without sanitization
  • Privilege escalation: Commands run with the current user's privileges
  • Data exfiltration: All command output is processed and logged as-is
  • Shell metacharacters: No filtering of shell special characters

Best Practices

  1. Never pass untrusted user input as command arguments to logwrap
  2. Validate commands before wrapping them with logwrap
  3. Review log output visibility before exposing logs publicly
  4. Disable user/PID in templates for public-facing logs (see below)
  5. Useexamples/public-safe.yaml as a starting point for shared environments
  6. Avoid running logwrap as root unless necessary

Information Disclosure

LogWrap's default configuration includes user and process information in output:

[2024-01-15 14:30:00] INFO alice@12345: Application started
^^^^^ ^^^^^
username PID

When this matters:

  • CI/CD logs exposed publicly (GitHub Actions, GitLab CI)
  • Logs sent to shared dashboards (Splunk, ELK, Datadog)
  • Error logs included in bug reports
  • Logs stored in cloud services

How to disable:

CLI:

# Use template without user/PID variables
logwrap -template '[{{.Timestamp}}] {{.Level}}: ' -- command

Config file:

prefix:
template: "[{{.Timestamp}}] {{.Level}}: "user:
enabled: falsepid:
enabled: false

See examples/public-safe.yaml for a complete configuration safe for public/shared logging environments.

References

Performance

LogWrap is designed for minimal overhead:

  • Real-time processing with no buffering delays
  • Efficient memory usage with buffer reuse
  • Concurrent processing of stdout/stderr streams
  • Minimal CPU impact on wrapped commands

Troubleshooting

Common Issues

  1. Command not found: Ensure the command is in your PATH
  2. Configuration errors: Validate your YAML syntax
  3. Permission denied: Check file permissions for config files
  4. Color issues: Some terminals may not support ANSI colors

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

  • Create an issue for bug reports or feature requests
  • Check existing issues before creating new ones
  • Provide detailed information including OS, Go version, and configuration

About

Command execution wrapper that adds configurable prefixes to log output streams with real-time formatting (timestamps, log levels, colors, user info, PID)

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages