github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/datasource/columns.go (about) 1 // Copyright 2024 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package datasource 16 17 import ( 18 "fmt" 19 "reflect" 20 "slices" 21 "strconv" 22 "unsafe" 23 24 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns" 25 "github.com/inspektor-gadget/inspektor-gadget/pkg/columns/ellipsis" 26 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api" 27 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets" 28 metadatav1 "github.com/inspektor-gadget/inspektor-gadget/pkg/metadata/v1" 29 "github.com/inspektor-gadget/inspektor-gadget/pkg/parser" 30 ) 31 32 type DataTuple struct { 33 ds DataSource 34 data *data 35 } 36 37 func NewDataTuple(ds DataSource, d Data) *DataTuple { 38 return &DataTuple{ 39 ds: ds, 40 data: d.(*data), 41 } 42 } 43 44 func (ds *dataSource) Parser() (parser.Parser, error) { 45 cols, err := ds.Columns() 46 if err != nil { 47 return nil, err 48 } 49 return parser.NewParser(cols), nil 50 } 51 52 func (ds *dataSource) Columns() (*columns.Columns[DataTuple], error) { 53 cols, err := columns.NewColumns[DataTuple]() 54 if err != nil { 55 return nil, err 56 } 57 58 for i, f := range ds.fields { 59 if FieldFlagEmpty.In(f.Flags) || FieldFlagUnreferenced.In(f.Flags) { 60 continue 61 } 62 63 attributes := &columns.Attributes{ 64 Name: f.FullName, 65 Tags: f.Tags, 66 Visible: !FieldFlagHidden.In(f.Flags), 67 Width: columns.GetDefault().DefaultWidth, 68 Order: i * 100, 69 } 70 71 df := columns.DynamicField{ 72 Attributes: attributes, 73 Offset: uintptr(f.Offs), 74 } 75 76 // extract attributes from annotations 77 for k, v := range f.Annotations { 78 switch k { 79 case "columns.alignment": 80 switch metadatav1.Alignment(v) { 81 case metadatav1.AlignmentLeft: 82 attributes.Alignment = columns.AlignLeft 83 case metadatav1.AlignmentRight: 84 attributes.Alignment = columns.AlignRight 85 default: 86 return nil, fmt.Errorf("invalid alignment type for column %q: %s", f.Name, v) 87 } 88 case "columns.ellipsis": 89 switch metadatav1.EllipsisType(v) { 90 case metadatav1.EllipsisNone: 91 attributes.EllipsisType = ellipsis.None 92 case metadatav1.EllipsisStart: 93 attributes.EllipsisType = ellipsis.Start 94 case metadatav1.EllipsisMiddle: 95 attributes.EllipsisType = ellipsis.Middle 96 case metadatav1.EllipsisEnd: 97 attributes.EllipsisType = ellipsis.End 98 default: 99 return nil, fmt.Errorf("invalid ellipsis type for column %q: %s", f.Name, v) 100 } 101 case "columns.width": 102 var err error 103 attributes.Width, err = strconv.Atoi(v) 104 if err != nil { 105 return nil, fmt.Errorf("reading width for column %q: %w", f.Name, err) 106 } 107 case "columns.minWidth": 108 var err error 109 attributes.MinWidth, err = strconv.Atoi(v) 110 if err != nil { 111 return nil, fmt.Errorf("reading minWidth for column %q: %w", f.Name, err) 112 } 113 case "columns.maxWidth": 114 var err error 115 attributes.MaxWidth, err = strconv.Atoi(v) 116 if err != nil { 117 return nil, fmt.Errorf("reading maxWidth for column %q: %w", f.Name, err) 118 } 119 case "columns.template": 120 attributes.Template = v 121 df.Template = v 122 case "columns.fixed": 123 if v == "true" { 124 attributes.FixedWidth = true 125 } 126 } 127 } 128 129 if f.ReflectType() == nil { 130 df.Type = reflect.TypeOf([]byte{}) 131 132 acc := &fieldAccessor{ 133 ds: ds, 134 f: f, 135 } 136 fromC := slices.Contains(f.Tags, api.TagSrcEbpf) 137 err := cols.AddColumn(*df.Attributes, func(d *DataTuple) any { 138 if d.data == nil { 139 return "" 140 } 141 142 if fromC { 143 return gadgets.FromCString(acc.Get(d.data)) 144 } 145 return string(acc.Get(d.data)) 146 }) 147 if err != nil { 148 return nil, fmt.Errorf("creating columns: %w", err) 149 } 150 continue 151 } 152 153 if attributes.Width == 0 { 154 attributes.Width = columns.GetWidthFromType(f.ReflectType().Kind()) 155 } 156 157 df.Type = f.ReflectType() 158 idx := f.PayloadIndex 159 160 err := cols.AddFields([]columns.DynamicField{df}, func(d *DataTuple) unsafe.Pointer { 161 if len(d.data.Payload[idx]) == 0 { 162 return nil 163 } 164 return unsafe.Pointer(&d.data.Payload[idx][0]) 165 }) 166 if err != nil { 167 return nil, fmt.Errorf("creating columns: %w", err) 168 } 169 } 170 return cols, nil 171 }