github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/logger/adapter.go (about)

     1  package logger // import "github.com/Prakhar-Agarwal-byte/moby/daemon/logger"
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/containerd/log"
    12  	"github.com/Prakhar-Agarwal-byte/moby/api/types/plugins/logdriver"
    13  	"github.com/Prakhar-Agarwal-byte/moby/pkg/plugingetter"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // pluginAdapter takes a plugin and implements the Logger interface for logger
    18  // instances
    19  type pluginAdapter struct {
    20  	driverName   string
    21  	id           string
    22  	plugin       logPlugin
    23  	fifoPath     string
    24  	capabilities Capability
    25  	logInfo      Info
    26  
    27  	// synchronize access to the log stream and shared buffer
    28  	mu     sync.Mutex
    29  	enc    logdriver.LogEntryEncoder
    30  	stream io.WriteCloser
    31  	// buf is shared for each `Log()` call to reduce allocations.
    32  	// buf must be protected by mutex
    33  	buf logdriver.LogEntry
    34  }
    35  
    36  func (a *pluginAdapter) Log(msg *Message) error {
    37  	a.mu.Lock()
    38  
    39  	a.buf.Line = msg.Line
    40  	a.buf.TimeNano = msg.Timestamp.UnixNano()
    41  	a.buf.Partial = msg.PLogMetaData != nil
    42  	a.buf.Source = msg.Source
    43  	if msg.PLogMetaData != nil {
    44  		a.buf.PartialLogMetadata = &logdriver.PartialLogEntryMetadata{
    45  			Id:      msg.PLogMetaData.ID,
    46  			Last:    msg.PLogMetaData.Last,
    47  			Ordinal: int32(msg.PLogMetaData.Ordinal),
    48  		}
    49  	}
    50  
    51  	err := a.enc.Encode(&a.buf)
    52  	a.buf.Reset()
    53  
    54  	a.mu.Unlock()
    55  
    56  	PutMessage(msg)
    57  	return err
    58  }
    59  
    60  func (a *pluginAdapter) Name() string {
    61  	return a.driverName
    62  }
    63  
    64  func (a *pluginAdapter) Close() error {
    65  	a.mu.Lock()
    66  	defer a.mu.Unlock()
    67  
    68  	if err := a.plugin.StopLogging(filepath.Join("/", "run", "docker", "logging", a.id)); err != nil {
    69  		return err
    70  	}
    71  
    72  	if err := a.stream.Close(); err != nil {
    73  		log.G(context.TODO()).WithError(err).Error("error closing plugin fifo")
    74  	}
    75  	if err := os.Remove(a.fifoPath); err != nil && !os.IsNotExist(err) {
    76  		log.G(context.TODO()).WithError(err).Error("error cleaning up plugin fifo")
    77  	}
    78  
    79  	// may be nil, especially for unit tests
    80  	if pluginGetter != nil {
    81  		pluginGetter.Get(a.Name(), extName, plugingetter.Release)
    82  	}
    83  	return nil
    84  }
    85  
    86  type pluginAdapterWithRead struct {
    87  	*pluginAdapter
    88  }
    89  
    90  func (a *pluginAdapterWithRead) ReadLogs(config ReadConfig) *LogWatcher {
    91  	watcher := NewLogWatcher()
    92  
    93  	go func() {
    94  		defer close(watcher.Msg)
    95  		stream, err := a.plugin.ReadLogs(a.logInfo, config)
    96  		if err != nil {
    97  			watcher.Err <- errors.Wrap(err, "error getting log reader")
    98  			return
    99  		}
   100  		defer stream.Close()
   101  
   102  		dec := logdriver.NewLogEntryDecoder(stream)
   103  		for {
   104  			var buf logdriver.LogEntry
   105  			if err := dec.Decode(&buf); err != nil {
   106  				if err == io.EOF {
   107  					return
   108  				}
   109  				watcher.Err <- errors.Wrap(err, "error decoding log message")
   110  				return
   111  			}
   112  
   113  			msg := &Message{
   114  				Timestamp: time.Unix(0, buf.TimeNano),
   115  				Line:      buf.Line,
   116  				Source:    buf.Source,
   117  			}
   118  
   119  			// plugin should handle this, but check just in case
   120  			if !config.Since.IsZero() && msg.Timestamp.Before(config.Since) {
   121  				continue
   122  			}
   123  			if !config.Until.IsZero() && msg.Timestamp.After(config.Until) {
   124  				return
   125  			}
   126  
   127  			// send the message unless the consumer is gone
   128  			select {
   129  			case watcher.Msg <- msg:
   130  			case <-watcher.WatchConsumerGone():
   131  				return
   132  			}
   133  		}
   134  	}()
   135  
   136  	return watcher
   137  }