-
Notifications
You must be signed in to change notification settings - Fork 178
/
program_logger.go
165 lines (132 loc) · 4.87 KB
/
program_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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package environment
import (
"time"
"github.com/onflow/cadence/runtime/common"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/attribute"
"github.com/onflow/flow-go/module/trace"
)
// MetricsReporter captures and reports metrics to back to the execution
// environment it is a setup passed to the context.
type MetricsReporter interface {
RuntimeTransactionParsed(time.Duration)
RuntimeTransactionChecked(time.Duration)
RuntimeTransactionInterpreted(time.Duration)
RuntimeSetNumberOfAccounts(count uint64)
RuntimeTransactionProgramsCacheMiss()
RuntimeTransactionProgramsCacheHit()
}
// NoopMetricsReporter is a MetricReporter that does nothing.
type NoopMetricsReporter struct{}
// RuntimeTransactionParsed is a noop
func (NoopMetricsReporter) RuntimeTransactionParsed(time.Duration) {}
// RuntimeTransactionChecked is a noop
func (NoopMetricsReporter) RuntimeTransactionChecked(time.Duration) {}
// RuntimeTransactionInterpreted is a noop
func (NoopMetricsReporter) RuntimeTransactionInterpreted(time.Duration) {}
// RuntimeSetNumberOfAccounts is a noop
func (NoopMetricsReporter) RuntimeSetNumberOfAccounts(count uint64) {}
// RuntimeTransactionProgramsCacheMiss is a noop
func (NoopMetricsReporter) RuntimeTransactionProgramsCacheMiss() {}
// RuntimeTransactionProgramsCacheHit is a noop
func (NoopMetricsReporter) RuntimeTransactionProgramsCacheHit() {}
type ProgramLoggerParams struct {
zerolog.Logger
CadenceLoggingEnabled bool
MetricsReporter
}
func DefaultProgramLoggerParams() ProgramLoggerParams {
return ProgramLoggerParams{
Logger: zerolog.Nop(),
CadenceLoggingEnabled: false,
MetricsReporter: NoopMetricsReporter{},
}
}
type ProgramLogger struct {
tracer *Tracer
ProgramLoggerParams
logs []string
}
func NewProgramLogger(
tracer *Tracer,
params ProgramLoggerParams,
) *ProgramLogger {
return &ProgramLogger{
tracer: tracer,
ProgramLoggerParams: params,
logs: nil,
}
}
func (logger *ProgramLogger) Logger() *zerolog.Logger {
return &logger.ProgramLoggerParams.Logger
}
func (logger *ProgramLogger) ImplementationDebugLog(message string) error {
logger.Logger().Debug().Msgf("Cadence: %s", message)
return nil
}
func (logger *ProgramLogger) ProgramLog(message string) error {
defer logger.tracer.StartExtensiveTracingSpanFromRoot(trace.FVMEnvProgramLog).End()
if logger.CadenceLoggingEnabled {
logger.logs = append(logger.logs, message)
}
return nil
}
func (logger *ProgramLogger) Logs() []string {
return logger.logs
}
func (logger *ProgramLogger) RecordTrace(operation string, location common.Location, duration time.Duration, attrs []attribute.KeyValue) {
if location != nil {
attrs = append(attrs, attribute.String("location", location.String()))
}
logger.tracer.RecordSpanFromRoot(
trace.FVMCadenceTrace.Child(operation),
duration,
attrs)
}
// ProgramParsed captures time spent on parsing a code at specific location
func (logger *ProgramLogger) ProgramParsed(location common.Location, duration time.Duration) {
logger.RecordTrace("parseProgram", location, duration, nil)
// These checks prevent re-reporting durations, the metrics collection is
// a bit counter-intuitive:
// The three functions (parsing, checking, interpretation) are not called
// in sequence, but in some cases as part of each other. We basically only
// measure the durations reported for the entry-point (the transaction),
// and not for child locations, because they might be already part of the
// duration for the entry-point.
if location == nil {
return
}
if _, ok := location.(common.TransactionLocation); ok {
logger.MetricsReporter.RuntimeTransactionParsed(duration)
}
}
// ProgramChecked captures time spent on checking a code at specific location
func (logger *ProgramLogger) ProgramChecked(location common.Location, duration time.Duration) {
logger.RecordTrace("checkProgram", location, duration, nil)
// see the comment for ProgramParsed
if location == nil {
return
}
if _, ok := location.(common.TransactionLocation); ok {
logger.MetricsReporter.RuntimeTransactionChecked(duration)
}
}
// ProgramInterpreted captures time spent on interpreting a code at specific location
func (logger *ProgramLogger) ProgramInterpreted(location common.Location, duration time.Duration) {
logger.RecordTrace("interpretProgram", location, duration, nil)
// see the comment for ProgramInterpreted
if location == nil {
return
}
if _, ok := location.(common.TransactionLocation); ok {
logger.MetricsReporter.RuntimeTransactionInterpreted(duration)
}
}
// ValueEncoded accumulates time spend on runtime value encoding
func (logger *ProgramLogger) ValueEncoded(duration time.Duration) {
logger.RecordTrace("encodeValue", nil, duration, nil)
}
// ValueDecoded accumulates time spend on runtime value decoding
func (logger *ProgramLogger) ValueDecoded(duration time.Duration) {
logger.RecordTrace("decodeValue", nil, duration, nil)
}