Could you please add Printf(format string, a ...interface{}) method to the Progress class? Thus it would be possible to print messages, not related to the progress bars, as using simple fmt.Println() corrupts the output.
Something similar to Python tqdm's write() method.
Oh, it also should be safe to use after p.Wait() is called and returned.
For now I've found this workaround, but I suppose the inner implementation would be much more optimized, as it could avoid extra progress bar creation and panic-recovers. Code below is based on the poplog example, however, bars are not popped in this situation.
```Golang
package main
import (
"fmt"
"math/rand"
"time"
"github.com/vbauerster/mpb/v6"
"github.com/vbauerster/mpb/v6/decor"
)
func main() {
p := mpb.New(mpb.PopCompletedMode())
// This is the function, that prints the message
printf := func(format string, a ...interface{}) {
msg := fmt.Sprintf(format, a...)
// As p.Add() panics after p.Wait() is returned, we should
// use reserve method to guarantee the output
defer func() {
if r := recover(); r != nil {
fmt.Println("fmt.Println():", msg)
}
}()
p.Add(0, nil, mpb.PrependDecorators(decor.Name("printf(): "+msg))).SetTotal(0, true)
}
// Simulating some output, not related to the progress bars
ticker := time.NewTicker(200 * time.Millisecond)
go func() {
defer ticker.Stop()
for n := 0; ; n++ {
<-ticker.C
printf("%v", n)
}
}()
total, numBars := 100, 4
for i := 0; i < numBars; i++ {
name := fmt.Sprintf("Bar#%d:", i)
bar := p.AddBar(int64(total),
mpb.BarFillerOnComplete(fmt.Sprintf("%s has been completed", name)),
mpb.BarFillerTrim(),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(name), ""),
decor.OnComplete(decor.NewPercentage(" % d "), ""),
),
mpb.AppendDecorators(
decor.OnComplete(decor.Name(" "), ""),
decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""),
),
mpb.BarNoPop(),
)
// simulating some work
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
max := 10 * time.Millisecond
for i := 0; i < total; i++ {
// start variable is solely for EWMA calculation
// EWMA's unit of measure is an iteration's duration
start := time.Now()
time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
bar.Increment()
// we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract
bar.DecoratorEwmaUpdate(time.Since(start))
}
}
p.Wait()
// After p.Wait() printf() will panic and recover
time.Sleep(500 * time.Millisecond)
}
```
Output:
```
printf(): 0
printf(): 1
printf(): 2
printf(): 3
printf(): 4
printf(): 5
printf(): 6
printf(): 7
printf(): 8
printf(): 9
printf(): 10
printf(): 11
printf(): 12
printf(): 13
printf(): 14
printf(): 15
printf(): 16
printf(): 17
printf(): 18
printf(): 19
printf(): 20
printf(): 21
printf(): 22
printf(): 23
printf(): 24
printf(): 25
printf(): 26
printf(): 27
printf(): 28
printf(): 29
printf(): 30
Bar#0: has been completed
Bar#1: has been completed
Bar#2: has been completed
Bar#3: has been completed
fmt.Println(): 31
fmt.Println(): 32
```
Hello!
Could you please add
Printf(format string, a ...interface{})
method to theProgress
class? Thus it would be possible to print messages, not related to the progress bars, as using simplefmt.Println()
corrupts the output. Something similar to Python tqdm's write() method.Oh, it also should be safe to use after
p.Wait()
is called and returned.For now I've found this workaround, but I suppose the inner implementation would be much more optimized, as it could avoid extra progress bar creation and panic-recovers. Code below is based on the poplog example, however, bars are not popped in this situation.
```Golang package main import ( "fmt" "math/rand" "time" "github.com/vbauerster/mpb/v6" "github.com/vbauerster/mpb/v6/decor" ) func main() { p := mpb.New(mpb.PopCompletedMode()) // This is the function, that prints the message printf := func(format string, a ...interface{}) { msg := fmt.Sprintf(format, a...) // As p.Add() panics after p.Wait() is returned, we should // use reserve method to guarantee the output defer func() { if r := recover(); r != nil { fmt.Println("fmt.Println():", msg) } }() p.Add(0, nil, mpb.PrependDecorators(decor.Name("printf(): "+msg))).SetTotal(0, true) } // Simulating some output, not related to the progress bars ticker := time.NewTicker(200 * time.Millisecond) go func() { defer ticker.Stop() for n := 0; ; n++ { <-ticker.C printf("%v", n) } }() total, numBars := 100, 4 for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.BarFillerOnComplete(fmt.Sprintf("%s has been completed", name)), mpb.BarFillerTrim(), mpb.PrependDecorators( decor.OnComplete(decor.Name(name), ""), decor.OnComplete(decor.NewPercentage(" % d "), ""), ), mpb.AppendDecorators( decor.OnComplete(decor.Name(" "), ""), decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""), ), mpb.BarNoPop(), ) // simulating some work rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 10 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } } p.Wait() // After p.Wait() printf() will panic and recover time.Sleep(500 * time.Millisecond) } ```Output:
``` printf(): 0 printf(): 1 printf(): 2 printf(): 3 printf(): 4 printf(): 5 printf(): 6 printf(): 7 printf(): 8 printf(): 9 printf(): 10 printf(): 11 printf(): 12 printf(): 13 printf(): 14 printf(): 15 printf(): 16 printf(): 17 printf(): 18 printf(): 19 printf(): 20 printf(): 21 printf(): 22 printf(): 23 printf(): 24 printf(): 25 printf(): 26 printf(): 27 printf(): 28 printf(): 29 printf(): 30 Bar#0: has been completed Bar#1: has been completed Bar#2: has been completed Bar#3: has been completed fmt.Println(): 31 fmt.Println(): 32 ```