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  }