Documentation ¶
Index ¶
- type LineWriter
- type LogsReader
- type Object
- type TailOption
- func WithTailComponentName(val string) TailOption
- func WithTailContainerName(val string) TailOption
- func WithTailFollow(val bool) TailOption
- func WithTailLabels(val map[string]string) TailOption
- func WithTailNumberLines(val int) TailOption
- func WithTailSpace(val string) TailOption
- func WithTailTimeout(val time.Duration) TailOption
- type TailOptions
- func (opts TailOptions) ComponentName() string
- func (opts TailOptions) ContainerName() string
- func (opts TailOptions) Extend(other TailOptions) TailOptions
- func (opts TailOptions) Follow() bool
- func (opts TailOptions) Labels() map[string]string
- func (opts TailOptions) NumberLines() int
- func (opts TailOptions) Space() string
- func (opts TailOptions) Timeout() time.Duration
- type Tailer
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type LineWriter ¶
type LineWriter struct { Writer io.Writer sync.Mutex // NumberOfLines is a VERY simple (hacky) way for us to ensure only the // set number of lines is written to stdout. NumberOfLines int }
LineWriter contains writer with a mutex instance. It is VERY opinionated on how it writes to the underlying writer. It counts lines and will STOP writing to the underlying writer if a limit is set.
type LogsReader ¶
type LogsReader struct {
// contains filtered or unexported fields
}
LogsReader is used to read logs from an Object (e.g., App, Build, Task).
func NewLogsReader ¶
func NewLogsReader(client kubernetes.Interface) *LogsReader
NewLogsReader returns a new LogsReader object.
func (*LogsReader) Follow ¶
func (l *LogsReader) Follow(ctx context.Context, o Object, since time.Time) (<-chan string, <-chan error)
Follow watches for matching pods, reads from them until they reach a completed stage (Succeeded/Failed). The resulting channel is closed when the context is marked done.
func (*LogsReader) Recent ¶
Recent returns the given number of log lines for the configured labels.
NOTE: To future developers or even myself... I'd like to explain some of the decisions made here. There are a few things that look/feel less than optimal. That is because they are. Let me explain:
First, let's explain each abstraction: 1. WindowedLogReader - This reads time windows from an individual containere on a Pod. Each block is sorted in ascending order before being returned. 2. ReverseLogReader - This returns the most logs in descending order from a container. It writes each log to an enqueuer. It does this by managing a sliding window and requesting that time block from the WindowedLogReader. 3. LogReader - This is the main object. It fetches all the matching Pods and creates a queue for each of their containers. It then creates a ReverseLogReader and has it write their logs to the given queue. Each ReverseLogReader will fill up their queue (and block). On the main go-routine, it will look at each queue to see who has the latest entry. It will pick that one and dequeue from it. This process repeats until we have enough logs or the client bails.
Second, let's talk about the queue: The queue is a simple wrapper around a channel. Read operations are non-blocking. If the queue is empty, they will return nil. Read operations include Dequeue and Peek. Enqueue however, will block. Therefore it must take and adhere to a context so that it can be properly canceled.o
Third, let's talk about what I would have rather done (and why I didn't):
* Instead of queues, I would have preferred priority-queues. I could have avoided sorting and potentially reading blocks in general. This fell flat though because channels. Our context (the type and concept) uses a channel to denote when it is done. Therefore, it becomes difficult to NOT use channels to coordinate go-routines. So for example, when I want to write to my priority-queue and its full, how do I unblock when it is read from? Normally, a conditional mutex would be appropriate. However, my context has a channel, so I would need to coordinate between a mutex and a channel. The main way I can tell to do this is by starting a go-routine to wait for the channel to be closed. However, this also implies that for each write I would have to create a go-routine. Ultimately, I became exceedingly nervous I was going to leak go-routines.
* I would have liked to avoid reading in blocks of time. In the WindowedLogReader, I use time and read until I reach a certain point in time. Ideally, I could only read a certain number of lines (to avoid reading in too much data into memory). However, given the K8s API, we can only start a stream at a certain point in time and start reading forward. This makes it tough to reach a set amount of lines.
All this is to say, this can be improved upon, but hopefully you can save some time and not go down the same wrong paths I did.
type Object ¶
type Object interface { metav1.Object // LogSelector returns the selector used to find the Pods that will be // fetched or watched for logs. If we are following, then follow will be // true. LogSelector(follow bool) string }
Object is an object that can have logs belong to it (or one of its children). This is implemented by Kf's CR's (e.g., App).
type TailOption ¶
type TailOption func(*tailConfig)
TailOption is a single option for configuring a tailConfig
func WithTailComponentName ¶
func WithTailComponentName(val string) TailOption
WithTailComponentName creates an Option that sets Name of the component to pull logs from.
func WithTailContainerName ¶
func WithTailContainerName(val string) TailOption
WithTailContainerName creates an Option that sets Container name to pull logs from.
func WithTailFollow ¶
func WithTailFollow(val bool) TailOption
WithTailFollow creates an Option that sets stream the logs
func WithTailLabels ¶
func WithTailLabels(val map[string]string) TailOption
WithTailLabels creates an Option that sets Labels to filter the Pods when tailing logs.
func WithTailNumberLines ¶
func WithTailNumberLines(val int) TailOption
WithTailNumberLines creates an Option that sets number of lines
func WithTailSpace ¶
func WithTailSpace(val string) TailOption
WithTailSpace creates an Option that sets the Space to use
func WithTailTimeout ¶
func WithTailTimeout(val time.Duration) TailOption
WithTailTimeout creates an Option that sets How much time to wait before giving up when not following.
type TailOptions ¶
type TailOptions []TailOption
TailOptions is a configuration set defining a tailConfig
func TailOptionDefaults ¶
func TailOptionDefaults() TailOptions
TailOptionDefaults gets the default values for Tail.
func (TailOptions) ComponentName ¶
func (opts TailOptions) ComponentName() string
ComponentName returns the last set value for ComponentName or the empty value if not set.
func (TailOptions) ContainerName ¶
func (opts TailOptions) ContainerName() string
ContainerName returns the last set value for ContainerName or the empty value if not set.
func (TailOptions) Extend ¶
func (opts TailOptions) Extend(other TailOptions) TailOptions
Extend creates a new TailOptions with the contents of other overriding the values set in this TailOptions.
func (TailOptions) Follow ¶
func (opts TailOptions) Follow() bool
Follow returns the last set value for Follow or the empty value if not set.
func (TailOptions) Labels ¶
func (opts TailOptions) Labels() map[string]string
Labels returns the last set value for Labels or the empty value if not set.
func (TailOptions) NumberLines ¶
func (opts TailOptions) NumberLines() int
NumberLines returns the last set value for NumberLines or the empty value if not set.
func (TailOptions) Space ¶
func (opts TailOptions) Space() string
Space returns the last set value for Space or the empty value if not set.
func (TailOptions) Timeout ¶
func (opts TailOptions) Timeout() time.Duration
Timeout returns the last set value for Timeout or the empty value if not set.