Documentation
¶
Overview ¶
Package columns is a library that helps to carry data structs in a more generic way using a combination of reflection and generics. It can work with any type of struct (and arrays of those), providing useful functions like sorting, grouping, filtering and printing. How columns are handled can be configured using tags along the struct definition. This keeps metadata and type data in the same place, avoiding extra and/or duplicated code and thereby the likelihood of typos/errors.
Columns just has to be initialized by passing a prototype of the struct. Afterwards you can use all helper functions (sorting, grouping, etc.) on it.
How does it work? ¶
You simply add a "column" tag to members of the struct you want to handle, like so:
type Event struct { Node string `json:"node" column:"node,width:12,ellipsis:middle"` PID int `json:"pid" column:"PID,hide,align:right,width:6"` Comm string `json:"comm" column:"Comm"` Name string `json:"name" column:"Name"` Dummy string `json:"dummy"` Time int64 `json:"time" column:"Time,align:right,width:24,group:sum"` }
Let's briefly analyze:
- All fields that have a column tag will be considered, that means the `Dummy` field will not be considered.
- Each column tag starts with the name of the field. This name is case-insensitive (and an error will be thrown if multiple fields share the same name.)
- Additional information on the fields are added as a comma separated list after the name of the column; key and value (if applicable) are separated by a colon (see `attributes` below)
You initialize `Columns` by passing it the type of the struct you want to use, like so:
cols, err := columns.NewColumns[Event]()
The parameter could be used for specific options, passing nil will use the defaults.
Attributes ¶
| Attribute | Value(s) | Description | |-----------|------------------------|----------------------------------------------------------------------------------------------------------------------| | align | left,right | defines the alignment of the column (whitespace before or after the value) | | ellipsis | none,left,right,middle | defines how situations of content exceeding the given space should be handled, eg: where to place the ellipsis ("…") | | fixed | none | defines that this column will have a fixed width, even when auto-scaling is enabled | | group | sum | defines what should happen with the field whenever entries are grouped (see grouping) | | hide | none | specifies that this column is not to be considered by default | | precision | int | specifies the precision of floats (number of decimals) | | width | int | defines the space allocated for the column |
Virtual Columns or Custom Extractors ¶
Sometimes it's necessary to add columns on the fly or have special treatment when extracting values. This can be achieved by specifying a virtual column or custom extractors.
Say that for example you have a struct with a (by default) not printable member `Foo` that you still want to output.
type Event struct { Node string `json:"node" column:"node,width:12,ellipsis:middle"` Foo []byte }
You can do that by adding a virtual column:
cols.AddColumn(columns.Attributes{ Name: "foo", Width: 14, }, func(e *Event) any { return string(e.Foo) })
This will convert the []byte to a string before printing it.
You can also just override the default extractor like so:
cols.SetExtractor("node", func(a *Event) any { return "Foobar" })
Example ¶
package main import ( "bytes" "fmt" "strings" "github.com/inspektor-gadget/inspektor-gadget/pkg/columns" "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/filter" "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/formatter/textcolumns" "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/sort" ) type Employee struct { Name string `column:"name" columnTags:"sensitive"` Age int `column:"age" columnTags:"sensitive"` Department string `column:"department"` } var Employees = []*Employee{ {"Alice", 32, "Security"}, {"Bob", 26, "Security"}, {"Eve", 99, "Security also"}, } // Defining the column helper here lets the program crash on start if there are // errors in the syntax var employeeColumns = columns.MustCreateColumns[Employee]() func main() { out := bytes.NewBuffer(nil) // Get columnMap cmap := employeeColumns.GetColumnMap() // Get a new formatter formatter := textcolumns.NewFormatter(cmap, textcolumns.WithRowDivider(textcolumns.DividerDash)) // Output the whole table formatter.WriteTable(out, Employees) out.WriteString("\n") // Reverse the order by name and output again sort.SortEntries[Employee](cmap, Employees, []string{"-name"}) formatter.WriteTable(out, Employees) out.WriteString("\n") // Now only get security personell securityOnly, err := filter.FilterEntries[Employee](cmap, Employees, []string{"department:Security"}) if err != nil { panic(err) } formatter.WriteTable(out, securityOnly) out.WriteString("\n") // Confidentiality! formatter = textcolumns.NewFormatter(employeeColumns.GetColumnMap(columns.WithoutTag("sensitive")), textcolumns.WithRowDivider(textcolumns.DividerDash)) formatter.WriteTable(out, securityOnly) // Split output by newline and remove whitespace at the end of each line to match test output below outLines := strings.Split(out.String(), "\n") for _, line := range outLines { fmt.Println(strings.TrimRight(line, " ")) } }
Output: NAME AGE DEPARTMENT —————————————————————————————————————————————————— Alice 32 Security Bob 26 Security Eve 99 Security also NAME AGE DEPARTMENT —————————————————————————————————————————————————— Eve 99 Security also Bob 26 Security Alice 32 Security NAME AGE DEPARTMENT —————————————————————————————————————————————————— Bob 26 Security Alice 32 Security DEPARTMENT ———————————————— Security Security
Index ¶
- Constants
- func GetFieldAsArrayFunc[OT any, T any](column ColumnInternals) func(entry *T) []OT
- func GetFieldAsNumberFunc[OT constraints.Integer | constraints.Float, T any](column ColumnInternals) func(entry *T) OT
- func GetFieldAsString[T any](column ColumnInternals) func(entry *T) string
- func GetFieldAsStringExt[T any](column ColumnInternals, floatFormat byte, floatPrecision int, hex bool) func(entry *T) string
- func GetFieldFunc[OT any, T any](column ColumnInternals) func(entry *T) OT
- func GetFieldFuncExt[OT any, T any](column ColumnInternals, raw bool) func(entry *T) OT
- func GetWidthFromType(kind reflect.Kind) int
- func MustRegisterTemplate(name, value string)
- func RegisterTemplate(name, value string) error
- func SetFieldAsNumberFunc[OT constraints.Integer | constraints.Float, T any](column ColumnInternals) func(entry *T, value OT)
- func SetFieldFunc[OT any, T any](column ColumnInternals) func(entry *T, val OT)
- func ToLowerStrings(in []string) []string
- type Alignment
- type Attributes
- type Column
- func (ci *Column[T]) Get(entry *T) reflect.Value
- func (ci *Column[T]) GetAttributes() *Attributes
- func (ci *Column[T]) GetRaw(entry *T) reflect.Value
- func (ci *Column[T]) GetRef(v reflect.Value) reflect.Value
- func (ci *Column[T]) HasCustomExtractor() bool
- func (ci *Column[T]) HasNoTags() bool
- func (ci *Column[T]) HasTag(tag string) bool
- func (ci *Column[T]) IsEmbedded() bool
- func (ci *Column[T]) IsVirtual() bool
- func (ci *Column[T]) Kind() reflect.Kind
- func (ci *Column[T]) RawType() reflect.Type
- func (ci *Column[T]) Type() reflect.Type
- type ColumnFilter
- func And(filters ...ColumnFilter) ColumnFilter
- func Or(filters ...ColumnFilter) ColumnFilter
- func WithAnyTag(tags []string) ColumnFilter
- func WithEmbedded(embedded bool) ColumnFilter
- func WithNoTags() ColumnFilter
- func WithTag(tag string) ColumnFilter
- func WithTags(tags []string) ColumnFilter
- func WithoutExceptTag(tag, exception string) ColumnFilter
- func WithoutTag(tag string) ColumnFilter
- func WithoutTags(tags []string) ColumnFilter
- type ColumnInterface
- type ColumnInternals
- type ColumnMap
- func (c ColumnMap[T]) GetColumn(columnName string) (*Column[T], bool)
- func (c ColumnMap[T]) GetColumnMap(filters ...ColumnFilter) ColumnMap[T]
- func (c ColumnMap[T]) GetColumnNames(filters ...ColumnFilter) []string
- func (c ColumnMap[T]) GetOrderedColumns(filters ...ColumnFilter) []*Column[T]
- func (c ColumnMap[T]) VerifyColumnNames(columnNames []string) (valid []string, invalid []string)
- type ColumnMatcher
- type Columns
- func (c *Columns[T]) AddColumn(attributes Attributes, extractor func(*T) any) error
- func (c *Columns[T]) AddFields(fields []DynamicField, base func(*T) unsafe.Pointer) error
- func (c *Columns[T]) MustAddColumn(attributes Attributes, extractor func(*T) any)
- func (c *Columns[T]) MustSetExtractor(columnName string, extractor func(*T) any)
- func (c *Columns[T]) SetExtractor(columnName string, extractor func(*T) any) error
- type DynamicField
- type GroupType
- type Option
- type Options
- type Order
Examples ¶
Constants ¶
const ( MaxCharsUint8 = 3 // 255 MaxCharsInt8 = 4 // -128 MaxCharsUint16 = 5 // 65535 MaxCharsInt16 = 6 // -32768 MaxCharsUint32 = 10 // 4294967295 MaxCharsInt32 = 11 // -2147483648 MaxCharsUint64 = 20 // 18446744073709551615 MaxCharsInt64 = 20 // −9223372036854775808 MaxCharsBool = 5 // false MaxCharsChar = 1 // 1 character )
Variables ¶
This section is empty.
Functions ¶
func GetFieldAsArrayFunc ¶ added in v0.19.0
func GetFieldAsArrayFunc[OT any, T any](column ColumnInternals) func(entry *T) []OT
GetFieldAsArrayFunc returns a helper function to access an array of type OT of a struct T without using reflection. It does not differentiate between direct members of the struct and members of embedded structs.
func GetFieldAsNumberFunc ¶ added in v0.17.0
func GetFieldAsNumberFunc[OT constraints.Integer | constraints.Float, T any](column ColumnInternals) func(entry *T) OT
GetFieldAsNumberFunc returns a helper function to access a field of struct T as a number.
func GetFieldAsString ¶ added in v0.18.0
func GetFieldAsString[T any](column ColumnInternals) func(entry *T) string
func GetFieldAsStringExt ¶ added in v0.18.0
func GetFieldFunc ¶ added in v0.17.0
func GetFieldFunc[OT any, T any](column ColumnInternals) func(entry *T) OT
GetFieldFunc returns a helper function to access the value of type OT of a struct T without using reflection. It differentiates between direct members of the struct and members of embedded structs. If any of the embedded structs being accessed is a nil-pointer, the default value of OT will be returned. Custom extractors will be preferred.
func GetFieldFuncExt ¶ added in v0.18.0
func GetFieldFuncExt[OT any, T any](column ColumnInternals, raw bool) func(entry *T) OT
GetFieldFuncExt returns a helper function to access the value of type OT of a struct T without using reflection. It differentiates between direct members of the struct and members of embedded structs. If any of the embedded structs being accessed is a nil-pointer, the default value of OT will be returned. If raw is set, even if a custom extractor has been set, the returned func will access the underlying values.
func GetWidthFromType ¶ added in v0.26.0
func MustRegisterTemplate ¶
func MustRegisterTemplate(name, value string)
MustRegisterTemplate calls RegisterTemplate and will panic if an error occurs.
func RegisterTemplate ¶
RegisterTemplate registers the column settings template in value to name. Whenever a column has "template:name" set, this template will be used. Plausibility and syntax checks will only be applied when the template gets used.
func SetFieldAsNumberFunc ¶ added in v0.18.0
func SetFieldAsNumberFunc[OT constraints.Integer | constraints.Float, T any](column ColumnInternals) func(entry *T, value OT)
SetFieldAsNumberFunc returns a helper function to set a field of struct T to a number.
func SetFieldFunc ¶ added in v0.18.0
func SetFieldFunc[OT any, T any](column ColumnInternals) func(entry *T, val OT)
SetFieldFunc returns a helper function to set the value of type OT to a member of struct T without using reflection. It differentiates between direct members of the struct and members of embedded structs. If any of the embedded structs being accessed is a nil-pointer, no value will be set
func ToLowerStrings ¶
ToLowerStrings transforms the elements of an array of strings into lowercase.
Types ¶
type Alignment ¶
type Alignment int
Alignment defines whether text should be aligned to the left or right inside a column
type Attributes ¶ added in v0.17.0
type Attributes struct { // Name of the column; case-insensitive for most use cases; includes inherited prefixes Name string `yaml:"name"` // Name of the columns without inherited prefixes RawName string `yaml:"raw_name"` // Alias is an alternative shorter name to be used for header of the column; if not set, the Name will be used Alias string `yaml:"alias"` // Width to reserve for this column Width int `yaml:"width"` // MinWidth will be the minimum width this column will be scaled to when using auto-scaling MinWidth int `yaml:"min_width"` // MaxWidth will be the maximum width this column will be scaled to when using auto-scaling MaxWidth int `yaml:"max_width"` // Alignment of this column (left or right) Alignment Alignment `yaml:"alignment"` // Visible defines whether a column is to be shown by default Visible bool `yaml:"visible"` // GroupType defines the aggregation method used when grouping this column GroupType GroupType `yaml:"group_type"` // EllipsisType defines how to abbreviate this column if the value needs more space than is available EllipsisType ellipsis.EllipsisType `yaml:"ellipsis_type"` // FixedWidth forces the Width even when using Auto-Scaling FixedWidth bool `yaml:"fixed_width"` // Precision defines how many decimals should be shown on float values, default: 2 Precision int `yaml:"precision"` // Hex defines whether the value should be shown as a hexadecimal number Hex bool `yaml:"hex"` // Description can hold a short description of the field that can be used to aid the user Description string `yaml:"description"` // Order defines the default order in which columns are shown Order int `yaml:"order"` // Tags can be used to dynamically include or exclude columns Tags []string `yaml:"tags"` // Template defines the template that will be used. Non-typed templates will be applied first. Template string `yaml:"template"` }
type Column ¶
type Column[T any] struct { Attributes Extractor func(*T) any // Extractor to be used; this can be defined to transform the output before retrieving the actual value // contains filtered or unexported fields }
func (*Column[T]) Get ¶
Get returns the reflected value of an entry for the current column; if given nil, it will return the zero value of the underlying type
func (*Column[T]) GetAttributes ¶ added in v0.17.0
func (ci *Column[T]) GetAttributes() *Attributes
func (*Column[T]) GetRaw ¶
GetRaw returns the reflected value of an entry for the current column without evaluating the extractor func; if given nil or run on a virtual or manually added column, it will return the zero value of the underlying type. If using embedded structs via pointers and the embedded value is nil, it will also return the zero value of the underlying type.
func (*Column[T]) GetRef ¶
GetRef returns the reflected value of an already reflected entry for the current column; expects v to be valid or will panic
func (*Column[T]) HasCustomExtractor ¶ added in v0.11.0
HasCustomExtractor returns true, if the column has a user defined extractor set
func (*Column[T]) IsEmbedded ¶
IsEmbedded returns true, if the current column is a member of an embedded struct
func (*Column[T]) IsVirtual ¶ added in v0.11.0
IsVirtual returns true, if the column has direct reference to a field
func (*Column[T]) Kind ¶
Kind returns the underlying kind of the column (always reflect.String in case of virtual columns)
type ColumnFilter ¶
type ColumnFilter func(matcher ColumnMatcher) bool
func And ¶
func And(filters ...ColumnFilter) ColumnFilter
And combines several ColumnFilter and matches if all filters match
func Or ¶
func Or(filters ...ColumnFilter) ColumnFilter
Or combines several ColumnFilter and matches if one filter matches
func WithAnyTag ¶ added in v0.21.0
func WithAnyTag(tags []string) ColumnFilter
WithAnyTag makes sure that all returned columns contain at least one of the given tags
func WithEmbedded ¶
func WithEmbedded(embedded bool) ColumnFilter
WithEmbedded checks whether a column matches the embedded criteria
func WithNoTags ¶
func WithNoTags() ColumnFilter
WithNoTags makes sure that all returned columns contain no tags
func WithTag ¶
func WithTag(tag string) ColumnFilter
WithTag makes sure that all returned columns contain all the given tag
func WithTags ¶
func WithTags(tags []string) ColumnFilter
WithTags makes sure that all returned columns contain all the given tags
func WithoutExceptTag ¶ added in v0.17.0
func WithoutExceptTag(tag, exception string) ColumnFilter
WithoutExceptTag makes sure that all returned columns don't contain the given tag, except when it also includes the exception given
func WithoutTag ¶
func WithoutTag(tag string) ColumnFilter
WithoutTag makes sure that all returned columns don't contain the given tag
func WithoutTags ¶
func WithoutTags(tags []string) ColumnFilter
WithoutTags makes sure that all returned columns contain none of the given tags
type ColumnInterface ¶
type ColumnInterface[T any] interface { GetColumn(columnName string) (*Column[T], bool) GetColumnMap(filters ...ColumnFilter) ColumnMap[T] GetOrderedColumns(filters ...ColumnFilter) []*Column[T] GetColumnNames(filters ...ColumnFilter) []string }
ColumnInterface is an interface that is valid for Columns and ColumnMap
type ColumnInternals ¶ added in v0.17.0
type ColumnInternals interface { IsVirtual() bool HasCustomExtractor() bool // contains filtered or unexported methods }
ColumnInternals is a non-generic interface to return internal values of columns like offsets for faster access.
type ColumnMap ¶
func (ColumnMap[T]) GetColumnMap ¶
func (c ColumnMap[T]) GetColumnMap(filters ...ColumnFilter) ColumnMap[T]
GetColumnMap returns a map of column names to their Column, filtered by filters
func (ColumnMap[T]) GetColumnNames ¶
func (c ColumnMap[T]) GetColumnNames(filters ...ColumnFilter) []string
GetColumnNames returns a list of column names, ordered by the column order values
func (ColumnMap[T]) GetOrderedColumns ¶
func (c ColumnMap[T]) GetOrderedColumns(filters ...ColumnFilter) []*Column[T]
GetOrderedColumns returns an ordered list of columns according to their order values, filtered by filters
func (ColumnMap[T]) VerifyColumnNames ¶
VerifyColumnNames takes a list of column names and returns two lists, one containing the valid column names and another containing the invalid column names. Prefixes like "-" for descending sorting will be ignored.
type ColumnMatcher ¶
type Columns ¶
type Columns[T any] struct { // columns map[string]*Column[T] ColumnMap[T] // contains filtered or unexported fields }
func MustCreateColumns ¶
MustCreateColumns creates a new column helper and panics if it cannot successfully be created; useful if you want to initialize Columns as a global variable inside a package (similar to regexp.MustCompile)
func NewColumns ¶
NewColumns creates a new column helper. T must be of type struct and its fields must have a column tag if they should be considered. Struct and pointer to struct fields will be recursively traversed by default unless a column tag with parameter "noembed" is present. Options can be passed to change the default behavior.
func (*Columns[T]) AddColumn ¶
func (c *Columns[T]) AddColumn(attributes Attributes, extractor func(*T) any) error
AddColumn adds a virtual column to the table. This virtual column requires at least a name and an Extractor
func (*Columns[T]) AddFields ¶ added in v0.18.0
func (c *Columns[T]) AddFields(fields []DynamicField, base func(*T) unsafe.Pointer) error
func (*Columns[T]) MustAddColumn ¶
func (c *Columns[T]) MustAddColumn(attributes Attributes, extractor func(*T) any)
MustAddColumn adds a new column and panics if it cannot successfully do so
func (*Columns[T]) MustSetExtractor ¶
MustSetExtractor adds a new extractor to a column and panics if it cannot successfully do so
type DynamicField ¶ added in v0.18.0
type DynamicField struct { Attributes *Attributes Tag string Template string Type reflect.Type Offset uintptr }
DynamicField manually describes fields this library should be able to access. Combined with the DynamicPtr interface, this can be used to access fields for example in a byte slice. Either Attributes or a Tag has to be set - if both are set, Tag takes precedence over the Attributes.
type GroupType ¶
type GroupType int
GroupType defines how columns should be aggregated in case of grouping
type Option ¶
type Option func(*Options)
func WithAlignment ¶
WithAlignment sets the default alignment
func WithEllipsis ¶
func WithEllipsis(e ellipsis.EllipsisType) Option
WithEllipsis sets the default ellipsis type
func WithRequireColumnDefinition ¶
WithRequireColumnDefinition sets whether the library should handle struct members without a column tag
type Options ¶
type Options struct { DefaultAlignment Alignment // default text alignment to use; default AlignLeft DefaultEllipsis ellipsis.EllipsisType // default type of ellipsis to use for overflowing text; default: ellipsis.End DefaultWidth int // width to be used when no width is specified for a column; default: 16 RequireColumnDefinition bool // if set to false, Columns will consider all struct members, regardless of the column tag (in backticks behind the struct field, like `column:"columnName"`) being present; default: true }
func GetDefault ¶
func GetDefault() *Options
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package ellipsis helps to truncate text at a specific width and adding an optional ellipsis ("…") to indicate that the text has been truncated.
|
Package ellipsis helps to truncate text at a specific width and adding an optional ellipsis ("…") to indicate that the text has been truncated. |
examples
|
|
Package filter helps filtering an array of structs that were analyzed by the columns library.
|
Package filter helps filtering an array of structs that were analyzed by the columns library. |
formatter
|
|
textcolumns
Package textcolumns helps to output structs (and events of structs) using metadata from a `Columns` instance in a tabular way suitable for consoles or other frontends using fixed-width characters / fonts.
|
Package textcolumns helps to output structs (and events of structs) using metadata from a `Columns` instance in a tabular way suitable for consoles or other frontends using fixed-width characters / fonts. |
Package group can group the entries of an array by one or more columns.
|
Package group can group the entries of an array by one or more columns. |
Package sort can be used to sort an array by their columns in either ascending or descending order.
|
Package sort can be used to sort an array by their columns in either ascending or descending order. |