177 lines
4.1 KiB
Go
177 lines
4.1 KiB
Go
// Package nvidia_bug_report provides parser for NVIDIA bug report files
|
|
// Generated by nvidia-bug-report.sh script
|
|
package nvidia_bug_report
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
"git.mchus.pro/mchus/logpile/internal/parser"
|
|
)
|
|
|
|
// parserVersion - version of this parser module
|
|
const parserVersion = "1.1.0"
|
|
|
|
var bugReportDateLineRegex = regexp.MustCompile(`(?m)^Date:\s+(.+?)\s*$`)
|
|
var dateWithTZAbbrevRegex = regexp.MustCompile(`^([A-Za-z]{3}\s+[A-Za-z]{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+([A-Za-z]{2,5})\s+(\d{4})$`)
|
|
|
|
var timezoneAbbrevToOffset = map[string]string{
|
|
"UTC": "+00:00",
|
|
"GMT": "+00:00",
|
|
"EST": "-05:00",
|
|
"EDT": "-04:00",
|
|
"CST": "-06:00",
|
|
"CDT": "-05:00",
|
|
"MST": "-07:00",
|
|
"MDT": "-06:00",
|
|
"PST": "-08:00",
|
|
"PDT": "-07:00",
|
|
}
|
|
|
|
func init() {
|
|
parser.Register(&Parser{})
|
|
}
|
|
|
|
// Parser implements VendorParser for NVIDIA bug reports
|
|
type Parser struct{}
|
|
|
|
// Name returns human-readable parser name
|
|
func (p *Parser) Name() string {
|
|
return "NVIDIA Bug Report Parser"
|
|
}
|
|
|
|
// Vendor returns vendor identifier
|
|
func (p *Parser) Vendor() string {
|
|
return "nvidia_bug_report"
|
|
}
|
|
|
|
// Version returns parser version
|
|
func (p *Parser) Version() string {
|
|
return parserVersion
|
|
}
|
|
|
|
// Detect checks if this is an NVIDIA bug report
|
|
// Returns confidence 0-100
|
|
func (p *Parser) Detect(files []parser.ExtractedFile) int {
|
|
// Only detect if there's exactly one file
|
|
if len(files) != 1 {
|
|
return 0
|
|
}
|
|
|
|
file := files[0]
|
|
|
|
// Check filename
|
|
if !strings.Contains(strings.ToLower(file.Path), "nvidia-bug-report") {
|
|
return 0
|
|
}
|
|
|
|
// Check content markers
|
|
content := string(file.Content)
|
|
if !strings.Contains(content, "nvidia-bug-report.sh") ||
|
|
!strings.Contains(content, "NVIDIA bug report log file") {
|
|
return 0
|
|
}
|
|
|
|
// High confidence for nvidia-bug-report files
|
|
return 85
|
|
}
|
|
|
|
// Parse parses NVIDIA bug report file
|
|
func (p *Parser) Parse(files []parser.ExtractedFile) (*models.AnalysisResult, error) {
|
|
result := &models.AnalysisResult{
|
|
Events: make([]models.Event, 0),
|
|
FRU: make([]models.FRUInfo, 0),
|
|
Sensors: make([]models.SensorReading, 0),
|
|
}
|
|
|
|
// Initialize hardware config
|
|
result.Hardware = &models.HardwareConfig{
|
|
CPUs: make([]models.CPU, 0),
|
|
Memory: make([]models.MemoryDIMM, 0),
|
|
GPUs: make([]models.GPU, 0),
|
|
PowerSupply: make([]models.PSU, 0),
|
|
}
|
|
|
|
if len(files) == 0 {
|
|
return result, nil
|
|
}
|
|
|
|
content := string(files[0].Content)
|
|
if collectedAt, tzOffset, ok := parseBugReportCollectedAt(content); ok {
|
|
result.CollectedAt = collectedAt.UTC()
|
|
result.SourceTimezone = tzOffset
|
|
}
|
|
|
|
// Parse system information
|
|
parseSystemInfo(content, result)
|
|
|
|
// Parse CPU information
|
|
parseCPUInfo(content, result)
|
|
|
|
// Parse memory modules
|
|
parseMemoryModules(content, result)
|
|
|
|
// Parse power supplies
|
|
parsePSUInfo(content, result)
|
|
|
|
// Parse GPU information
|
|
parseGPUInfo(content, result)
|
|
|
|
// Parse network adapters
|
|
parseNetworkAdapters(content, result)
|
|
|
|
// Parse driver version
|
|
parseDriverVersion(content, result)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func parseBugReportCollectedAt(content string) (time.Time, string, bool) {
|
|
matches := bugReportDateLineRegex.FindStringSubmatch(content)
|
|
if len(matches) != 2 {
|
|
return time.Time{}, "", false
|
|
}
|
|
raw := strings.TrimSpace(matches[1])
|
|
if raw == "" {
|
|
return time.Time{}, "", false
|
|
}
|
|
|
|
if m := dateWithTZAbbrevRegex.FindStringSubmatch(raw); len(m) == 4 {
|
|
if offset, ok := timezoneAbbrevToOffset[strings.ToUpper(strings.TrimSpace(m[2]))]; ok {
|
|
layout := "Mon Jan 2 15:04:05 -07:00 2006"
|
|
normalized := strings.TrimSpace(m[1]) + " " + offset + " " + strings.TrimSpace(m[3])
|
|
if ts, err := time.Parse(layout, normalized); err == nil {
|
|
return ts, offset, true
|
|
}
|
|
}
|
|
}
|
|
|
|
layouts := []string{
|
|
"Mon Jan 2 15:04:05 MST 2006",
|
|
"Mon Jan 2 15:04:05 2006",
|
|
}
|
|
for _, layout := range layouts {
|
|
ts, err := time.Parse(layout, raw)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
return ts, formatOffset(ts), true
|
|
}
|
|
return time.Time{}, "", false
|
|
}
|
|
|
|
func formatOffset(t time.Time) string {
|
|
_, sec := t.Zone()
|
|
sign := '+'
|
|
if sec < 0 {
|
|
sign = '-'
|
|
sec = -sec
|
|
}
|
|
h := sec / 3600
|
|
m := (sec % 3600) / 60
|
|
return fmt.Sprintf("%c%02d:%02d", sign, h, m)
|
|
}
|