-
Notifications
You must be signed in to change notification settings - Fork 0
/
transcript.go
140 lines (119 loc) · 3.61 KB
/
transcript.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
package common
import (
"context"
"fmt"
"reflect"
"go.opencensus.io/trace"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/insolar/payload"
"github.com/insolar/insolar/insolar/record"
"github.com/insolar/insolar/instrumentation/inslogger"
"github.com/insolar/insolar/instrumentation/instracer"
"github.com/insolar/insolar/logicrunner/artifacts"
)
type Transcript struct {
ObjectDescriptor artifacts.ObjectDescriptor
Context context.Context
LogicContext *insolar.LogicCallContext
Request *record.IncomingRequest
RequestRef insolar.Reference
Nonce uint64
Deactivate bool
OutgoingRequests []OutgoingRequest
FromLedger bool
}
func NewTranscript(
ctx context.Context,
requestRef insolar.Reference,
request record.IncomingRequest,
) *Transcript {
return &Transcript{
Context: ctx,
Request: &request,
RequestRef: requestRef,
Nonce: 0,
Deactivate: false,
FromLedger: false,
}
}
// NewTranscriptCloneContext creates a transcript with fresh context created from
// contextSource which can be either other Context or ServiceData. In general
// transcript shouldn't be created with context as execution can take minutes.
func NewTranscriptCloneContext(
ctxSource interface{},
requestRef insolar.Reference,
request record.IncomingRequest,
) *Transcript {
var ctx context.Context
switch sourceTyped := ctxSource.(type) {
case context.Context:
ctx = freshContextFromContext(sourceTyped, request.APIRequestID)
case *payload.ServiceData:
ctx = contextFromServiceData(sourceTyped)
default:
panic(fmt.Errorf("unexpected type of context source: %T", ctxSource))
}
objRef := request.Object
if objRef == nil {
objRef = &requestRef
}
ctx, _ = inslogger.WithFields(
ctx,
map[string]interface{}{
"request": requestRef.String(),
"object": objRef.String(),
"method": request.Method,
},
)
return NewTranscript(ctx, requestRef, request)
}
func (t *Transcript) AddOutgoingRequest(
ctx context.Context, request record.IncomingRequest, result []byte, newObject *insolar.Reference, err error,
) {
rec := OutgoingRequest{
Request: request,
Response: result,
NewObject: newObject,
Error: err,
}
t.OutgoingRequests = append(t.OutgoingRequests, rec)
}
func (t *Transcript) HasOutgoingRequest(
ctx context.Context, request record.IncomingRequest,
) *OutgoingRequest {
for i := range t.OutgoingRequests {
if reflect.DeepEqual(t.OutgoingRequests[i].Request, request) {
return &t.OutgoingRequests[i]
}
}
return nil
}
func contextFromServiceData(data *payload.ServiceData) context.Context {
ctx := inslogger.ContextWithTrace(context.Background(), data.LogTraceID)
ctx = inslogger.WithLoggerLevel(ctx, data.LogLevel)
if data.TraceSpanData != nil {
parentSpan := instracer.MustDeserialize(data.TraceSpanData)
return instracer.WithParentSpan(ctx, parentSpan)
}
return ctx
}
func freshContextFromContext(ctx context.Context, reqID string) context.Context {
res := context.Background()
res = inslogger.SetLogger(res, inslogger.FromContext(ctx))
logLevel := inslogger.GetLoggerLevel(ctx)
if logLevel != insolar.NoLevel {
res = inslogger.WithLoggerLevel(res, logLevel)
}
// we know that trace id is equal to APIRequestID, in a few cases we
// call this function and don't have correct context and trace id around
// except in request record as APIRequestID field
res = inslogger.ContextWithTrace(res, reqID)
parentSpan, ok := instracer.ParentSpan(ctx)
if ok {
res = instracer.WithParentSpan(res, parentSpan)
}
if pctx := trace.FromContext(ctx); pctx != nil {
res = trace.NewContext(res, pctx)
}
return res
}