1// Copyright (c) 2016 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package indexers
6
7import (
8	"sync"
9	"time"
10
11	"github.com/btcsuite/btclog"
12	"github.com/btcsuite/btcutil"
13)
14
15// blockProgressLogger provides periodic logging for other services in order
16// to show users progress of certain "actions" involving some or all current
17// blocks. Ex: syncing to best chain, indexing all blocks, etc.
18type blockProgressLogger struct {
19	receivedLogBlocks int64
20	receivedLogTx     int64
21	lastBlockLogTime  time.Time
22
23	subsystemLogger btclog.Logger
24	progressAction  string
25	sync.Mutex
26}
27
28// newBlockProgressLogger returns a new block progress logger.
29// The progress message is templated as follows:
30//  {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
31//  ({numTxs}, height {lastBlockHeight}, {lastBlockTimeStamp})
32func newBlockProgressLogger(progressMessage string, logger btclog.Logger) *blockProgressLogger {
33	return &blockProgressLogger{
34		lastBlockLogTime: time.Now(),
35		progressAction:   progressMessage,
36		subsystemLogger:  logger,
37	}
38}
39
40// LogBlockHeight logs a new block height as an information message to show
41// progress to the user. In order to prevent spam, it limits logging to one
42// message every 10 seconds with duration and totals included.
43func (b *blockProgressLogger) LogBlockHeight(block *btcutil.Block) {
44	b.Lock()
45	defer b.Unlock()
46
47	b.receivedLogBlocks++
48	b.receivedLogTx += int64(len(block.MsgBlock().Transactions))
49
50	now := time.Now()
51	duration := now.Sub(b.lastBlockLogTime)
52	if duration < time.Second*10 {
53		return
54	}
55
56	// Truncate the duration to 10s of milliseconds.
57	durationMillis := int64(duration / time.Millisecond)
58	tDuration := 10 * time.Millisecond * time.Duration(durationMillis/10)
59
60	// Log information about new block height.
61	blockStr := "blocks"
62	if b.receivedLogBlocks == 1 {
63		blockStr = "block"
64	}
65	txStr := "transactions"
66	if b.receivedLogTx == 1 {
67		txStr = "transaction"
68	}
69	b.subsystemLogger.Infof("%s %d %s in the last %s (%d %s, height %d, %s)",
70		b.progressAction, b.receivedLogBlocks, blockStr, tDuration, b.receivedLogTx,
71		txStr, block.Height(), block.MsgBlock().Header.Timestamp)
72
73	b.receivedLogBlocks = 0
74	b.receivedLogTx = 0
75	b.lastBlockLogTime = now
76}
77