Files
logpile/internal/exporter/exporter.go

224 lines
4.4 KiB
Go

package exporter
import (
"encoding/csv"
"encoding/json"
"io"
"strings"
"git.mchus.pro/mchus/logpile/internal/models"
)
// Exporter handles data export in various formats
type Exporter struct {
result *models.AnalysisResult
}
// New creates a new exporter
func New(result *models.AnalysisResult) *Exporter {
return &Exporter{result: result}
}
// ExportCSV exports serial numbers to CSV format
func (e *Exporter) ExportCSV(w io.Writer) error {
writer := csv.NewWriter(w)
defer writer.Flush()
// Header
if err := writer.Write([]string{"Component", "Serial Number", "Manufacturer", "Location"}); err != nil {
return err
}
if e.result == nil {
return nil
}
// FRU data
for _, fru := range e.result.FRU {
if !hasUsableSerial(fru.SerialNumber) {
continue
}
name := fru.ProductName
if name == "" {
name = fru.Description
}
if err := writer.Write([]string{
name,
fru.SerialNumber,
fru.Manufacturer,
fru.PartNumber,
}); err != nil {
return err
}
}
// Hardware data
if e.result.Hardware != nil {
// Board
if hasUsableSerial(e.result.Hardware.BoardInfo.SerialNumber) {
if err := writer.Write([]string{
e.result.Hardware.BoardInfo.ProductName,
strings.TrimSpace(e.result.Hardware.BoardInfo.SerialNumber),
e.result.Hardware.BoardInfo.Manufacturer,
"Board",
}); err != nil {
return err
}
}
// CPUs
for _, cpu := range e.result.Hardware.CPUs {
if !hasUsableSerial(cpu.SerialNumber) {
continue
}
if err := writer.Write([]string{
cpu.Model,
strings.TrimSpace(cpu.SerialNumber),
"",
"CPU",
}); err != nil {
return err
}
}
// Memory
for _, mem := range e.result.Hardware.Memory {
if !hasUsableSerial(mem.SerialNumber) {
continue
}
location := mem.Location
if location == "" {
location = mem.Slot
}
if err := writer.Write([]string{
mem.PartNumber,
strings.TrimSpace(mem.SerialNumber),
mem.Manufacturer,
location,
}); err != nil {
return err
}
}
// Storage
for _, stor := range e.result.Hardware.Storage {
if !hasUsableSerial(stor.SerialNumber) {
continue
}
if err := writer.Write([]string{
stor.Model,
strings.TrimSpace(stor.SerialNumber),
stor.Manufacturer,
stor.Slot,
}); err != nil {
return err
}
}
// GPUs
for _, gpu := range e.result.Hardware.GPUs {
if !hasUsableSerial(gpu.SerialNumber) {
continue
}
component := gpu.Model
if component == "" {
component = "GPU"
}
if err := writer.Write([]string{
component,
strings.TrimSpace(gpu.SerialNumber),
gpu.Manufacturer,
gpu.Slot,
}); err != nil {
return err
}
}
// PCIe devices
for _, pcie := range e.result.Hardware.PCIeDevices {
if !hasUsableSerial(pcie.SerialNumber) {
continue
}
if err := writer.Write([]string{
pcie.DeviceClass,
strings.TrimSpace(pcie.SerialNumber),
pcie.Manufacturer,
pcie.Slot,
}); err != nil {
return err
}
}
// Network adapters
for _, nic := range e.result.Hardware.NetworkAdapters {
if !hasUsableSerial(nic.SerialNumber) {
continue
}
location := nic.Location
if location == "" {
location = nic.Slot
}
if err := writer.Write([]string{
nic.Model,
strings.TrimSpace(nic.SerialNumber),
nic.Vendor,
location,
}); err != nil {
return err
}
}
// Legacy network cards
for _, nic := range e.result.Hardware.NetworkCards {
if !hasUsableSerial(nic.SerialNumber) {
continue
}
if err := writer.Write([]string{
nic.Model,
strings.TrimSpace(nic.SerialNumber),
"",
"Network",
}); err != nil {
return err
}
}
// Power supplies
for _, psu := range e.result.Hardware.PowerSupply {
if !hasUsableSerial(psu.SerialNumber) {
continue
}
if err := writer.Write([]string{
psu.Model,
strings.TrimSpace(psu.SerialNumber),
psu.Vendor,
psu.Slot,
}); err != nil {
return err
}
}
}
return nil
}
// ExportJSON exports all data to JSON format
func (e *Exporter) ExportJSON(w io.Writer) error {
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(e.result)
}
func hasUsableSerial(serial string) bool {
s := strings.TrimSpace(serial)
if s == "" {
return false
}
switch strings.ToUpper(s) {
case "N/A", "NA", "NONE", "NULL", "UNKNOWN", "-":
return false
default:
return true
}
}