pipes

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 16, 2023 License: GPL-3.0 Imports: 11 Imported by: 2

README

Logging through pipes

This functionality is needed when a parent process starts a child process and both their logs have to be collected in the parent process.

The parent process:

part, _ := pipes.NewParentPart(marshalizer)
profileReader, logsWriter := part.GetChildPipes()

command = exec.Command("child.bin")
childStdout, _:= command.StdoutPipe()
childStderr, _ := command.StderrPipe()
command.ExtraFiles = []*os.File{
		...,
		profileReader,
		logsWriter,
}

_ = part.StartLoop(childStdout, childStderr)

StartLoop will continuously read log lines from the child (pipe logsWriter) on a separate goroutine. Child's stdout and stderr are also captured. Stdout will be logged with trace level, while stderr with error level.

Furthermore, the parent part forwards log profile changes to the child process (through pipe profileReader).

Note that the parent process is responsible to call logger.NotifyProfileChange() when it applies a new log profile (whether by sole choice or when instructed by a logviewer).

The child process

profileReader := os.NewFile(42, "/proc/self/fd/42")
logsWriter := os.NewFile(43, "/proc/self/fd/43")
part, _ := pipes.NewChildPart(profileReader, logsWriter, marshalizer)
_ = part.StartLoop()

The child process has to acquire the provided pipes, create its part of the logging dialogue and then call StartLoop. The child part is automatically registered as observer to the global default LogOutputSubject, which means that it gets notified on each log write from any of the loggers in the process. When notified, the child part simply forwards the message (the serialized log line) to its parent, through pipe logsWriter.

Furthermore, the child part listens for eventual log profile changes on the pipe profileReader. Any profile change is applied immediately.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidOperationGivenPartLoopState = errors.New("invalid operation given state of loop")

ErrInvalidOperationGivenPartLoopState signals an error

Functions

func CreateErrUnmarshalLogLine

func CreateErrUnmarshalLogLine(marshalized []byte, originalErr error) error

CreateErrUnmarshalLogLine creates an error

func NewChildPart

func NewChildPart(
	profileReader *os.File,
	logsWriter *os.File,
	logLineMarshalizer logger.Marshalizer,
) (*childPart, error)

NewChildPart creates a new logs sender part (in the child process)

func NewParentPart

func NewParentPart(childName string, logLineMarshalizer logger.Marshalizer) (*parentPart, error)

NewParentPart creates a new logs receiver part (in the parent process)

Types

type ChildMessenger

type ChildMessenger struct {
	Messenger
}

ChildMessenger is the messenger on child's part of the pipe

func NewChildMessenger

func NewChildMessenger(profileReader *os.File, logsWriter *os.File) *ChildMessenger

NewChildMessenger creates a new messenger

func (*ChildMessenger) ReadProfile

func (messenger *ChildMessenger) ReadProfile() (logger.Profile, error)

ReadProfile reads an incoming profile

func (*ChildMessenger) SendLogLine

func (messenger *ChildMessenger) SendLogLine(logLineMarshalized []byte) (int, error)

SendLogLine sends a log line

type Messenger

type Messenger struct {
	// contains filtered or unexported fields
}

Messenger intermediates communication (message exchange) via pipes

func NewMessenger

func NewMessenger(reader *os.File, writer *os.File) *Messenger

NewMessenger creates a new messenger

func (*Messenger) ReadMessage

func (messenger *Messenger) ReadMessage() ([]byte, error)

ReadMessage reads a message from the pipe Reading messages is normally performed from a single go-routine, no mutex required

func (*Messenger) SendMessage

func (messenger *Messenger) SendMessage(message []byte) (int, error)

SendMessage sends a message over the pipe

type ParentMessenger

type ParentMessenger struct {
	Messenger
	// contains filtered or unexported fields
}

ParentMessenger is the messenger on parent's part of the pipe

func NewParentMessenger

func NewParentMessenger(logsReader *os.File, profileWriter *os.File, logLineMarshalizer logger.Marshalizer) *ParentMessenger

NewParentMessenger creates a new messenger

func (*ParentMessenger) ReadLogLine

func (messenger *ParentMessenger) ReadLogLine() (*logger.LogLine, error)

ReadLogLine reads a log line

func (*ParentMessenger) SendProfile

func (messenger *ParentMessenger) SendProfile(profile logger.Profile) error

SendProfile sends a profile

type PartLoopStateType

type PartLoopStateType = uint32

PartLoopStateType represents the state of a part (parent, child) loop

const (
	// PartLoopInit signals that loop hasn't been started yet
	PartLoopInit PartLoopStateType = iota
	// PartLoopRunning signals that a loop is running
	PartLoopRunning
	// PartLoopStopped signals that a loop is stopped
	PartLoopStopped
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL