Skip to content

blakesanie/progress

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🦦 blakesanie/progress

A lightweight and elegant Go package for real-time progress logging with automatic rate tracking, ETA estimation, and human-friendly formatting.

Ideal for command-line tools, data processing pipelines, and long-running batch jobs.


✨ Features

  • 🔁 Real-time updates (logged every second)
  • ⏱️ Tracks items per second (instantaneous and average)
  • 📈 Displays progress, percent complete, elapsed time, and ETA
  • 💬 Prints a clear summary when complete
  • 🔒 Thread-safe — works cleanly in concurrent contexts
  • 🧮 Human-readable numbers (e.g., 1.2K, 3.5M, 2.1B)
  • ⏳ Smart duration formatting (1m 23s, 2h 10m, etc.)

🚀 Installation

go get github.com/blakesanie/progress

Then, import it in your Go project:

import "github.com/blakesanie/progress"

💡 Quick Start

package main

import (
	"sync/atomic"
	"time"

	"github.com/blakesanie/progress"
)

func main() {
	var total int64 = 10_000
	pl := progress.NewProgressLogger("Processing", &total)

	for i := 0; i < int(total); i++ {
		pl.Add(1)
		time.Sleep(100 * time.Microsecond) // simulate work
	}

	// Optional: explicitly mark done (if total isn't provided or loop ends early)
	pl.Done()
}

Output (example):

Begin Processing
Processing: 4.8K/10.0K | 952/s | 48.0% | Elapsed 5s | ETA 5s
Processing: 9.9K/10.0K | 1.0K/s | 99.0% | Elapsed 10s | ETA 0s

======================================
Processing: Finished!
Total: 10.0K / 10.0K
Elapsed time: 10s
Average speed: 1.0K/s
======================================

Usage Examples

1. Known Total Workload

When you know how many units you’ll process, provide a pointer to the total count:

var total int64 = 5_000
pl := progress.NewProgressLogger("Downloading Files", &total)

As you process each item:

pl.Add(1)

The logger automatically stops when current == total.

2. Unknown or Streaming Workload

If you don’t know the total upfront, you can pass nil for the total:

pl := progress.NewProgressLogger("Streaming", nil)

Then, add progress dynamically:

pl.Add(50)

When your stream ends:

pl.Done()

Example output:

Begin Streaming
Streaming: 50 done | 25/s
Streaming: 100 done | 30/s

======================================
Streaming: Finished!
Total: 100
Elapsed time: 3s
Average speed: 33/s
======================================

🧵 Concurrency Safety

ProgressLogger is fully safe for concurrent updates.

You can safely call .Add() from multiple goroutines:

var total int64 = 1000
pl := progress.NewProgressLogger("Concurrent Tasks", &total)

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
	wg.Add(1)
	go func() {
		defer wg.Done()
		for j := 0; j < 100; j++ {
			pl.Add(1)
			time.Sleep(time.Millisecond)
		}
	}()
}

wg.Wait()
pl.Done()

🧩 API Reference

func NewProgressLogger(label string, total *int64) *ProgressLogger

Creates a new progress logger with the given label and optional total count.

func (pl *ProgressLogger) Add(n int64)

Increments progress by n units. If a total is defined and the total is reached, logging automatically stops.

func (pl *ProgressLogger) Done()

Stops the progress logger manually and prints a final summary. Useful for cases where the total is unknown or the operation ends early.

🧠 Implementation Details

  • Progress is printed every second (time.NewTicker(time.Second)).
  • Instantaneous rate (items/s) is computed from delta changes per tick.
  • Average speed is computed over the entire elapsed time.
  • Formatting functions:
    • formatNumber: Converts raw counts to readable suffixes (K, M, B, T)
    • formatDuration: Converts seconds into concise time strings.

🪪 License

MIT License © Blake Sanie

About

Clean and intuitive GoLang progress tracker via stdout.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages