-
Notifications
You must be signed in to change notification settings - Fork 288
/
logger.go
146 lines (127 loc) · 4.4 KB
/
logger.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package progresslog
import (
"sync"
"time"
"github.com/decred/dcrd/wire"
"github.com/decred/slog"
)
// pickNoun returns the singular or plural form of a noun depending on the
// provided count.
func pickNoun(n uint64, singular, plural string) string {
if n == 1 {
return singular
}
return plural
}
// Logger provides periodic logging of progress towards some action such as
// syncing the chain.
type Logger struct {
sync.Mutex
subsystemLogger slog.Logger
progressAction string
// lastLogTime tracks the last time a log statement was shown.
lastLogTime time.Time
// These fields accumulate information about blocks between log statements.
receivedBlocks uint64
receivedTxns uint64
receivedVotes uint64
receivedRevokes uint64
receivedTickets uint64
// These fields accumulate information about headers between log statements.
receivedHeaders uint64
}
// New returns a new block progress logger.
func New(progressAction string, logger slog.Logger) *Logger {
return &Logger{
lastLogTime: time.Now(),
progressAction: progressAction,
subsystemLogger: logger,
}
}
// LogProgress accumulates details for the provided block and periodically
// (every 10 seconds) logs an information message to show progress to the user
// along with duration and totals included.
//
// The force flag may be used to force a log message to be shown regardless of
// the time the last one was shown.
//
// The progress message is templated as follows:
//
// {progressAction} {numProcessed} {blocks|block} in the last {timePeriod}
// ({numTxs} {transactions|transaction}, {numTickets} {tickets|ticket},
// {numVotes} {votes|vote}, {numRevocations} {revocations|revocation},
// height {lastBlockHeight}, progress {progress}%)
//
// This function is safe for concurrent access.
func (l *Logger) LogProgress(block *wire.MsgBlock, forceLog bool, progressFn func() float64) {
l.Lock()
defer l.Unlock()
header := &block.Header
l.receivedBlocks++
l.receivedTxns += uint64(len(block.Transactions))
l.receivedVotes += uint64(header.Voters)
l.receivedRevokes += uint64(header.Revocations)
l.receivedTickets += uint64(header.FreshStake)
now := time.Now()
duration := now.Sub(l.lastLogTime)
if !forceLog && duration < time.Second*10 {
return
}
// Log information about chain progress.
l.subsystemLogger.Infof("%s %d %s in the last %0.2fs (%d %s, %d %s, %d %s, "+
"%d %s, height %d, progress %0.2f%%)", l.progressAction,
l.receivedBlocks, pickNoun(l.receivedBlocks, "block", "blocks"),
duration.Seconds(),
l.receivedTxns, pickNoun(l.receivedTxns, "transaction", "transactions"),
l.receivedTickets, pickNoun(l.receivedTickets, "ticket", "tickets"),
l.receivedVotes, pickNoun(l.receivedVotes, "vote", "votes"),
l.receivedRevokes, pickNoun(l.receivedRevokes, "revocation", "revocations"),
header.Height, progressFn())
l.receivedBlocks = 0
l.receivedTxns = 0
l.receivedVotes = 0
l.receivedTickets = 0
l.receivedRevokes = 0
l.lastLogTime = now
}
// LogHeaderProgress accumulates the provided number of processed headers and
// periodically (every 10 seconds) logs an information message to show the
// header sync progress to the user along with duration and totals included.
//
// The force flag may be used to force a log message to be shown regardless of
// the time the last one was shown.
//
// The progress message is templated as follows:
//
// {progressAction} {numProcessed} {headers|header} in the last {timePeriod}
// (progress {progress}%)
//
// This function is safe for concurrent access.
func (l *Logger) LogHeaderProgress(processedHeaders uint64, forceLog bool, progressFn func() float64) {
l.Lock()
defer l.Unlock()
l.receivedHeaders += processedHeaders
now := time.Now()
duration := now.Sub(l.lastLogTime)
if !forceLog && duration < time.Second*10 {
return
}
// Log information about header progress.
l.subsystemLogger.Infof("%s %d %s in the last %0.2fs (progress %0.2f%%)",
l.progressAction, l.receivedHeaders,
pickNoun(l.receivedHeaders, "header", "headers"),
duration.Seconds(), progressFn())
l.receivedHeaders = 0
l.lastLogTime = now
}
// SetLastLogTime updates the last time data was logged to the provided time.
//
// This function is safe for concurrent access.
func (l *Logger) SetLastLogTime(time time.Time) {
l.Lock()
l.lastLogTime = time
l.Unlock()
}