github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/events/logfile.go (about)

     1  package events
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/containers/storage"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  // EventLogFile is the structure for event writing to a logfile. It contains the eventer
    13  // options and the event itself.  Methods for reading and writing are also defined from it.
    14  type EventLogFile struct {
    15  	options EventerOptions
    16  }
    17  
    18  // Writes to the log file
    19  func (e EventLogFile) Write(ee Event) error {
    20  	// We need to lock events file
    21  	lock, err := storage.GetLockfile(e.options.LogFilePath + ".lock")
    22  	if err != nil {
    23  		return err
    24  	}
    25  	lock.Lock()
    26  	defer lock.Unlock()
    27  	f, err := os.OpenFile(e.options.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0700)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	defer f.Close()
    32  	eventJSONString, err := ee.ToJSONString()
    33  	if err != nil {
    34  		return err
    35  	}
    36  	if _, err := f.WriteString(fmt.Sprintf("%s\n", eventJSONString)); err != nil {
    37  		return err
    38  	}
    39  	return nil
    40  
    41  }
    42  
    43  // Reads from the log file
    44  func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
    45  	defer close(options.EventChannel)
    46  	eventOptions, err := generateEventOptions(options.Filters, options.Since, options.Until)
    47  	if err != nil {
    48  		return errors.Wrapf(err, "unable to generate event options")
    49  	}
    50  	t, err := e.getTail(options)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	funcDone := make(chan bool)
    55  	copy := true
    56  	go func() {
    57  		select {
    58  		case <-funcDone:
    59  			// Do nothing
    60  		case <-ctx.Done():
    61  			copy = false
    62  			t.Kill(errors.New("hangup by client"))
    63  		}
    64  	}()
    65  	for line := range t.Lines {
    66  		select {
    67  		case <-ctx.Done():
    68  			// the consumer has cancelled
    69  			return nil
    70  		default:
    71  			// fallthrough
    72  		}
    73  
    74  		event, err := newEventFromJSONString(line.Text)
    75  		if err != nil {
    76  			return err
    77  		}
    78  		switch event.Type {
    79  		case Image, Volume, Pod, System, Container, Network:
    80  		//	no-op
    81  		default:
    82  			return errors.Errorf("event type %s is not valid in %s", event.Type.String(), e.options.LogFilePath)
    83  		}
    84  		include := true
    85  		for _, filter := range eventOptions {
    86  			include = include && filter(event)
    87  		}
    88  		if include && copy {
    89  			options.EventChannel <- event
    90  		}
    91  	}
    92  	funcDone <- true
    93  	return nil
    94  }
    95  
    96  // String returns a string representation of the logger
    97  func (e EventLogFile) String() string {
    98  	return LogFile.String()
    99  }