A smart tool to upload log files to GitHub as Gists or Repositories
gh-upload-log is a CLI tool and JavaScript library that intelligently uploads log files to GitHub. It automatically determines the best upload strategy based on file size:
- Small files (≤100MB): Uploaded as GitHub Gists
- Large files (>100MB): Uploaded as GitHub Repositories with automatic splitting into 100MB chunks
- Automatic strategy selection: Chooses between Gist and Repository based on file size
- Smart file splitting: Automatically splits large files into manageable chunks
- Public/Private control: Upload as public or private (default: private)
- Flexible configuration: CLI arguments, environment variables, or
.lenvfiles using Links Notation - Cross-platform: Works on macOS, Linux, and Windows
- Dual interface: Use as CLI tool or JavaScript library
- Path normalization: Converts file paths into valid GitHub names
- Verbose logging: Built-in verbose mode using log-lazy for efficient lazy evaluation
- Configurable logging: Customize logging behavior with custom log targets (silent mode, custom loggers, etc.)
- Node.js ≥20.0.0
- Git (installed and configured)
- GitHub CLI (
gh) installed and authenticated
To authenticate with GitHub CLI:
gh auth loginnpm install -g gh-upload-lognpm install gh-upload-loggh-upload-log supports multiple configuration methods with the following priority (highest to lowest):
- CLI arguments - Directly passed command-line options
- Environment variables - System environment variables
.lenvfile - Local configuration using Links Notation format- Defaults - Built-in default values
The tool now supports .lenv configuration files using Links Notation format through lino-arguments.
Create a .lenv file in your project directory:
GH_UPLOAD_LOG_PUBLIC: false
GH_UPLOAD_LOG_VERBOSE: true
GH_UPLOAD_LOG_DESCRIPTION: Production logs
The configuration priority is:
- CLI arguments (highest priority)
- Environment variables
.lenvfile- Default values (lowest priority)
You can also specify a custom configuration file using the --configuration or -c flag:
gh-upload-log /path/to/file.log --configuration ./custom.lenvSet environment variables for persistent configuration:
export GH_UPLOAD_LOG_PUBLIC=true
export GH_UPLOAD_LOG_VERBOSE=true
export GH_UPLOAD_LOG_DESCRIPTION="Production logs"
gh-upload-log /var/log/app.logGH_UPLOAD_LOG_PUBLIC- Make uploads public (default: false)GH_UPLOAD_LOG_PRIVATE- Make uploads private (default: true)GH_UPLOAD_LOG_AUTO- Enable automatic strategy selection (default: true)GH_UPLOAD_LOG_ONLY_GIST- Force gist uploads only (default: false)GH_UPLOAD_LOG_ONLY_REPOSITORY- Force repository uploads only (default: false)GH_UPLOAD_LOG_DRY_MODE- Enable dry run mode (default: false)GH_UPLOAD_LOG_DESCRIPTION- Default description for uploadsGH_UPLOAD_LOG_VERBOSE- Enable verbose output (default: false)
See .lenv.example for a complete configuration template.
# Upload a log file (private by default)
gh-upload-log /path/to/logfile.log
# Upload as public
gh-upload-log /path/to/logfile.log --public
# Upload with description
gh-upload-log /path/to/logfile.log --description "My application logs"Usage: gh-upload-log <log-file> [options]
Options:
--public, -p Make the upload public (default: private)
--private Make the upload private (default)
--auto Automatically choose upload strategy (default: true)
--only-gist Upload only as GitHub Gist (disables auto mode)
--only-repository Upload only as GitHub Repository (disables auto mode)
--dry-mode, --dry Dry run - show what would be done without uploading
--description, -d Description for the upload
--verbose, -v Enable verbose output
--help, -h Show help
--version Show version number
# Upload private log file (auto mode)
gh-upload-log /var/log/app.log
# Upload public log file (auto mode)
gh-upload-log /var/log/app.log --public
# Upload only as gist
gh-upload-log ./error.log --only-gist
# Upload only as repository
gh-upload-log ./large.log --only-repository --public
# Dry run mode - see what would happen
gh-upload-log ./app.log --dry-mode
# Upload with custom description
gh-upload-log ./debug.log -d "Debug logs from production" --public
# Disable auto mode and force repository
gh-upload-log ./file.log --no-auto --only-repositoryimport { uploadLog } from 'gh-upload-log';
// Upload a log file (private by default)
const result = await uploadLog({
filePath: '/path/to/logfile.log'
});
console.log('Uploaded to:', result.url);
// Upload as public with verbose logging
const publicResult = await uploadLog({
filePath: '/path/to/logfile.log',
isPublic: true,
description: 'My application logs',
verbose: true
});
console.log('Public URL:', publicResult.url);
// Upload with custom logger (silent mode)
const customLogger = {
log: () => {}, // Silent logging
error: (msg) => console.error('ERROR:', msg)
};
const result = await uploadLog({
filePath: '/path/to/logfile.log',
logger: customLogger
});Main function to upload a log file. Automatically determines the best strategy.
Parameters:
options(object):filePath(string, required): Path to the log fileisPublic(boolean): Make upload public (default: false)auto(boolean): Automatically choose strategy (default: true)onlyGist(boolean): Upload only as gist (disables auto mode)onlyRepository(boolean): Upload only as repository (disables auto mode)dryMode(boolean): Dry run mode - don't actually uploaddescription(string): Description for the uploadverbose(boolean): Enable verbose logging (default: false)logger(object): Custom logging target (default: console)
Returns: Promise
{
type: 'gist' | 'repo',
url: string,
isPublic: boolean,
fileName?: string, // For gists
repositoryName?: string, // For repos
dryMode?: boolean // Set to true in dry mode
}Upload a file as a GitHub Gist.
Parameters:
options(object):filePath(string, required): Path to the fileisPublic(boolean): Make gist public (default: false)description(string): Gist descriptionverbose(boolean): Enable verbose logging (default: false)logger(object): Custom logging target (default: console)
Returns: Promise
Upload a file as a GitHub Repository (with splitting if needed).
Parameters:
options(object):filePath(string, required): Path to the fileisPublic(boolean): Make repo public (default: false)description(string): Repository descriptionverbose(boolean): Enable verbose logging (default: false)logger(object): Custom logging target (default: console)
Returns: Promise
Determine the best upload strategy for a file.
Parameters:
filePath(string): Path to the file
Returns: Object
{
type: 'gist' | 'repo',
fileSize: number,
needsSplit: boolean,
numChunks?: number, // For repos
reason: string
}normalizeFileName(filePath): Convert file path to GitHub-safe namegenerateRepoName(filePath): Generate repository name (withlog-prefix)generateGistFileName(filePath): Generate gist file namefileExists(filePath): Check if file existsgetFileSize(filePath): Get file size in bytes
import {
GITHUB_GIST_FILE_LIMIT, // 100 MB
GITHUB_GIST_WEB_LIMIT, // 25 MB
GITHUB_REPO_CHUNK_SIZE // 100 MB
} from 'gh-upload-log';File paths are normalized for GitHub compatibility:
- Leading slashes are removed
- All
/characters are replaced with- - Repository names are prefixed with
log-
Examples:
/home/user/app.log→ Gist:home-user-app.log, Repo:log-home-user-app./logs/error.log→ Gist:.-logs-error.log, Repo:log-.-logs-error
-
Files ≤100MB: Uploaded as GitHub Gist
- Single file upload
- Fast and efficient
- Viewable directly in browser
-
Files >100MB: Uploaded as GitHub Repository
- File is split into 100MB chunks
- Each chunk is committed to the repo
- Original file structure is preserved
By default, all uploads are private:
- Private Gists: Only accessible by you
- Private Repositories: Only accessible by you
Use --public flag or isPublic: true option for public uploads.
- Gist file limit: 100 MB (via git), 25 MB (via web interface)
- Repository size: No strict limit, but large repos may have performance issues
- Chunk size: Files are split into 100 MB chunks for repositories
Run tests using your preferred runtime:
# Node.js
npm test
# Bun
bun test
# Deno
deno test --allow-allSee the examples/ directory for more usage examples:
examples/basic-usage.js: Basic library usageexamples/library-api.js: API function examples
Run examples:
node examples/library-api.jsgh-upload-log/
├── src/
│ ├── index.js # Core library
│ └── cli.js # CLI interface
├── test/
│ └── index.test.js # Tests
├── examples/
│ ├── basic-usage.js
│ └── library-api.js
├── package.json
└── README.md
This project uses modern Link Foundation libraries:
- lino-arguments: CLI argument parsing with environment variable and .lenv file support
- log-lazy: Efficient lazy evaluation logging
- use-m: Dynamic module loading without package.json pollution
- command-stream: Streamable command execution
- test-anywhere: Universal testing framework (dev dependency)
The following libraries are used internally by lino-arguments:
- lino-env: Configuration management using Links Notation format
- links-notation: Data description using references and links
- yargs: Command-line argument parsing
Contributions are welcome! Please feel free to submit a Pull Request.
This is free and unencumbered software released into the public domain. See LICENSE for details.
- GitHub Repository: https://github.com/link-foundation/gh-upload-log
- Issue Tracker: https://github.com/link-foundation/gh-upload-log/issues
- Link Foundation: https://github.com/link-foundation
- lino-arguments - CLI argument parsing with environment variables and .lenv support
- lino-env - Configuration management using Links Notation
- links-notation - Data description using references and links
- log-lazy - Efficient lazy evaluation logging
- use-m - Dynamic module loading
- command-stream - Streamable commands
- test-anywhere - Universal testing