| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | // Copyright 2021 The Prometheus Authors
 | 
					
						
							|  |  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  |  | //
 | 
					
						
							|  |  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  | //
 | 
					
						
							|  |  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | //go:build linux && !nodmi
 | 
					
						
							|  |  |  |  | // +build linux,!nodmi
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | package collector | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"errors" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2021-12-01 02:13:43 -08:00
										 |  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  |  | 	"github.com/prometheus/procfs/sysfs" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type dmiCollector struct { | 
					
						
							|  |  |  |  | 	infoDesc *prometheus.Desc | 
					
						
							|  |  |  |  | 	values   []string | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func init() { | 
					
						
							|  |  |  |  | 	registerCollector("dmi", defaultEnabled, NewDMICollector) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewDMICollector returns a new Collector exposing DMI information.
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  |  | func NewDMICollector(logger *slog.Logger) (Collector, error) { | 
					
						
							| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | 	fs, err := sysfs.NewFS(*sysPath) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("failed to open sysfs: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	dmi, err := fs.DMIClass() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		if errors.Is(err, os.ErrNotExist) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  |  | 			logger.Debug("Platform does not support Desktop Management Interface (DMI) information", "err", err) | 
					
						
							| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | 			dmi = &sysfs.DMIClass{} | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			return nil, fmt.Errorf("failed to read Desktop Management Interface (DMI) information: %w", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	var labels, values []string | 
					
						
							|  |  |  |  | 	for label, value := range map[string]*string{ | 
					
						
							|  |  |  |  | 		"bios_date":         dmi.BiosDate, | 
					
						
							|  |  |  |  | 		"bios_release":      dmi.BiosRelease, | 
					
						
							|  |  |  |  | 		"bios_vendor":       dmi.BiosVendor, | 
					
						
							|  |  |  |  | 		"bios_version":      dmi.BiosVersion, | 
					
						
							|  |  |  |  | 		"board_asset_tag":   dmi.BoardAssetTag, | 
					
						
							|  |  |  |  | 		"board_name":        dmi.BoardName, | 
					
						
							|  |  |  |  | 		"board_serial":      dmi.BoardSerial, | 
					
						
							|  |  |  |  | 		"board_vendor":      dmi.BoardVendor, | 
					
						
							|  |  |  |  | 		"board_version":     dmi.BoardVersion, | 
					
						
							|  |  |  |  | 		"chassis_asset_tag": dmi.ChassisAssetTag, | 
					
						
							|  |  |  |  | 		"chassis_serial":    dmi.ChassisSerial, | 
					
						
							|  |  |  |  | 		"chassis_vendor":    dmi.ChassisVendor, | 
					
						
							|  |  |  |  | 		"chassis_version":   dmi.ChassisVersion, | 
					
						
							|  |  |  |  | 		"product_family":    dmi.ProductFamily, | 
					
						
							|  |  |  |  | 		"product_name":      dmi.ProductName, | 
					
						
							|  |  |  |  | 		"product_serial":    dmi.ProductSerial, | 
					
						
							|  |  |  |  | 		"product_sku":       dmi.ProductSKU, | 
					
						
							|  |  |  |  | 		"product_uuid":      dmi.ProductUUID, | 
					
						
							|  |  |  |  | 		"product_version":   dmi.ProductVersion, | 
					
						
							|  |  |  |  | 		"system_vendor":     dmi.SystemVendor, | 
					
						
							|  |  |  |  | 	} { | 
					
						
							|  |  |  |  | 		if value != nil { | 
					
						
							|  |  |  |  | 			labels = append(labels, label) | 
					
						
							| 
									
										
										
										
											2021-12-01 02:13:43 -08:00
										 |  |  |  | 			values = append(values, strings.ToValidUTF8(*value, "<22>")) | 
					
						
							| 
									
										
										
										
											2021-10-27 04:56:37 -07:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Construct DMI metric only once since it will not change until the next reboot.
 | 
					
						
							|  |  |  |  | 	return &dmiCollector{ | 
					
						
							|  |  |  |  | 		infoDesc: prometheus.NewDesc( | 
					
						
							|  |  |  |  | 			prometheus.BuildFQName(namespace, "dmi", "info"), | 
					
						
							|  |  |  |  | 			"A metric with a constant '1' value labeled by bios_date, bios_release, bios_vendor, bios_version, "+ | 
					
						
							|  |  |  |  | 				"board_asset_tag, board_name, board_serial, board_vendor, board_version, chassis_asset_tag, "+ | 
					
						
							|  |  |  |  | 				"chassis_serial, chassis_vendor, chassis_version, product_family, product_name, product_serial, "+ | 
					
						
							|  |  |  |  | 				"product_sku, product_uuid, product_version, system_vendor if provided by DMI.", | 
					
						
							|  |  |  |  | 			labels, nil, | 
					
						
							|  |  |  |  | 		), | 
					
						
							|  |  |  |  | 		values: values, | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (c *dmiCollector) Update(ch chan<- prometheus.Metric) error { | 
					
						
							|  |  |  |  | 	if len(c.values) == 0 { | 
					
						
							|  |  |  |  | 		return ErrNoData | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	ch <- prometheus.MustNewConstMetric(c.infoDesc, prometheus.GaugeValue, 1.0, c.values...) | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } |