github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/eventchannel/processor.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package eventchannel 16 17 import ( 18 "encoding/binary" 19 "fmt" 20 "io" 21 "os" 22 "time" 23 24 "google.golang.org/protobuf/proto" 25 "google.golang.org/protobuf/types/known/anypb" 26 pb "github.com/metacubex/gvisor/pkg/eventchannel/eventchannel_go_proto" 27 ) 28 29 // eventProcessor carries display state across multiple events. 30 type eventProcessor struct { 31 filtering bool 32 // filtered is the number of events omitted since printing the last matching 33 // event. Only meaningful when filtering == true. 34 filtered uint64 35 // allowlist is the set of event names to display. If empty, all events are 36 // displayed. 37 allowlist map[string]bool 38 } 39 40 // newEventProcessor creates a new EventProcessor with filters. 41 func newEventProcessor(filters []string) *eventProcessor { 42 e := &eventProcessor{ 43 filtering: len(filters) > 0, 44 allowlist: make(map[string]bool), 45 } 46 for _, f := range filters { 47 e.allowlist[f] = true 48 } 49 return e 50 } 51 52 // processOne reads, parses and displays a single event from the event channel. 53 // 54 // The event channel is a stream of (msglen, payload) packets; this function 55 // processes a single such packet. The msglen is a uvarint-encoded length for 56 // the associated payload. The payload is a binary-encoded 'Any' protobuf, which 57 // in turn encodes an arbitrary event protobuf. 58 func (e *eventProcessor) processOne(src io.Reader, out *os.File) error { 59 // Read and parse the msglen. 60 lenbuf := make([]byte, binary.MaxVarintLen64) 61 if _, err := io.ReadFull(src, lenbuf); err != nil { 62 return err 63 } 64 msglen, consumed := binary.Uvarint(lenbuf) 65 if consumed <= 0 { 66 return fmt.Errorf("couldn't parse the message length") 67 } 68 69 // Read the payload. 70 buf := make([]byte, msglen) 71 // Copy any unused bytes from the len buffer into the payload buffer. These 72 // bytes are actually part of the payload. 73 extraBytes := copy(buf, lenbuf[consumed:]) 74 if _, err := io.ReadFull(src, buf[extraBytes:]); err != nil { 75 return err 76 } 77 78 // Unmarshal the payload into an "Any" protobuf, which encodes the actual 79 // event. 80 encodedEv := anypb.Any{} 81 if err := proto.Unmarshal(buf, &encodedEv); err != nil { 82 return fmt.Errorf("failed to unmarshal 'any' protobuf message: %v", err) 83 } 84 85 var ev pb.DebugEvent 86 if err := encodedEv.UnmarshalTo(&ev); err != nil { 87 return fmt.Errorf("failed to decode 'any' protobuf message: %v", err) 88 } 89 90 if e.filtering && e.allowlist[ev.Name] { 91 e.filtered++ 92 return nil 93 } 94 95 if e.filtering && e.filtered > 0 { 96 if e.filtered == 1 { 97 fmt.Fprintf(out, "... filtered %d event ...\n\n", e.filtered) 98 } else { 99 fmt.Fprintf(out, "... filtered %d events ...\n\n", e.filtered) 100 } 101 e.filtered = 0 102 } 103 104 // Extract the inner event and display it. Example: 105 // 106 // 2017-10-04 14:35:05.316180374 -0700 PDT m=+1.132485846 107 // cloud_gvisor.MemoryUsage { 108 // total: 23822336 109 // } 110 fmt.Fprintf(out, "%v\n%v {\n", time.Now(), ev.Name) 111 fmt.Fprintf(out, "%v", ev.Text) 112 fmt.Fprintf(out, "}\n\n") 113 114 return nil 115 } 116 117 // ProcessAll reads, parses and displays all events from src. The events are 118 // displayed to out. 119 func ProcessAll(src io.Reader, filters []string, out *os.File) error { 120 ep := newEventProcessor(filters) 121 for { 122 switch err := ep.processOne(src, out); err { 123 case nil: 124 continue 125 case io.EOF: 126 return nil 127 default: 128 return err 129 } 130 } 131 }