Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

progressAsWriter with logrus does not work #141

Open
Blogoslov opened this issue Apr 5, 2024 · 2 comments
Open

progressAsWriter with logrus does not work #141

Blogoslov opened this issue Apr 5, 2024 · 2 comments

Comments

@Blogoslov
Copy link

Blogoslov commented Apr 5, 2024

Hello.
I have took this code from example and substitite standard logger to logrus but if failes with message:

Failed to write to log, *mpb.Progress instance can't be reused after *mpb.Progress.Wait()

package main

import (
	"fmt"
	"github.com/sirupsen/logrus"
	"math/rand"
	"sync"
	"time"

	"github.com/vbauerster/mpb/v8"
	"github.com/vbauerster/mpb/v8/decor"
)

var logger *logrus.Logger

func main() {
	log := logrus.New()
	total, numBars := 100, 2
	var wg sync.WaitGroup
	wg.Add(numBars)
	done := make(chan interface{})
	p := mpb.New(
		mpb.WithWidth(64),
		mpb.WithWaitGroup(&wg),
		mpb.WithShutdownNotifier(done),
	)

	log.SetOutput(p)

	for i := 0; i < numBars; i++ {
		name := fmt.Sprintf("Bar#%d:", i)
		bar := p.AddBar(int64(total),
			mpb.PrependDecorators(
				decor.Name(name),
				decor.Percentage(decor.WCSyncSpace),
			),
			mpb.AppendDecorators(
				decor.OnComplete(
					decor.EwmaETA(decor.ET_STYLE_GO, 30, decor.WCSyncWidth), "done",
				),
			),
		)
		// simulating some work
		go func() {
			defer wg.Done()
			rng := rand.New(rand.NewSource(time.Now().UnixNano()))
			max := 100 * 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)
				// we need to call EwmaIncrement to fulfill ewma decorator's contract
				bar.EwmaIncrement(time.Since(start))
			}
			log.Println(name, "done")
		}()
	}

	var qwg sync.WaitGroup
	qwg.Add(1)
	go func() {
	quit:
		for {
			select {
			case <-done:
				// after done, underlying io.Writer returns mpb.DoneError
				// so following isn't printed
				log.Println("all done")
				break quit
			default:
				log.Println("waiting for done")
				time.Sleep(100 * time.Millisecond)
			}
		}
		qwg.Done()
	}()

	p.Wait()
	qwg.Wait()
}

could you please suggest how to fix this?

@vbauerster
Copy link
Owner

Given that log's underlying io.Writer is *mpb.Progress, fix would be: don't call log after (*mpb.Progress).Wait(). To understand why ask yourself a question: what a logger should do when underlying io.Writer returns an error?

@Blogoslov
Copy link
Author

Blogoslov commented Apr 11, 2024

Sorry, but if I substitite "github.com/sirupsen/logrus" by builtin "log" package (as it was in your original example) - then I don't see such error message and this is why I opened the ticket. I expected that behaviour should be the same. Or not?

Could you please advise how to restore logger after p.Wait? I changed it by commpad log.SetOutput(p) and in my case the program is continue after p.Wait statement and do some other things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants