122 lines
2.8 KiB
Go
122 lines
2.8 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.mchus.pro/mchus/logpile/internal/models"
|
|
)
|
|
|
|
// BMCParser parses BMC diagnostic archives using vendor-specific parsers
|
|
type BMCParser struct {
|
|
result *models.AnalysisResult
|
|
files []ExtractedFile
|
|
vendorParser VendorParser
|
|
}
|
|
|
|
// NewBMCParser creates a new BMC parser
|
|
func NewBMCParser() *BMCParser {
|
|
return &BMCParser{
|
|
result: &models.AnalysisResult{
|
|
Events: make([]models.Event, 0),
|
|
FRU: make([]models.FRUInfo, 0),
|
|
Sensors: make([]models.SensorReading, 0),
|
|
},
|
|
}
|
|
}
|
|
|
|
// ParseArchive parses an archive file
|
|
func (p *BMCParser) ParseArchive(archivePath string) error {
|
|
files, err := ExtractArchive(archivePath)
|
|
if err != nil {
|
|
return fmt.Errorf("extract archive: %w", err)
|
|
}
|
|
p.files = files
|
|
return p.parseFiles()
|
|
}
|
|
|
|
// ParseFromReader parses archive from reader
|
|
func (p *BMCParser) ParseFromReader(r io.Reader, filename string) error {
|
|
files, err := ExtractArchiveFromReader(r, filename)
|
|
if err != nil {
|
|
return fmt.Errorf("extract archive: %w", err)
|
|
}
|
|
p.files = files
|
|
p.result.Filename = filename
|
|
return p.parseFiles()
|
|
}
|
|
|
|
func (p *BMCParser) parseFiles() error {
|
|
// Auto-detect format
|
|
vendorParser, err := DetectFormat(p.files)
|
|
if err != nil {
|
|
return fmt.Errorf("detect format: %w", err)
|
|
}
|
|
p.vendorParser = vendorParser
|
|
|
|
// Parse using detected vendor parser
|
|
result, err := vendorParser.Parse(p.files)
|
|
if err != nil {
|
|
return fmt.Errorf("parse with %s: %w", vendorParser.Name(), err)
|
|
}
|
|
|
|
// Preserve filename
|
|
result.Filename = p.result.Filename
|
|
|
|
appendExtractionWarnings(result, p.files)
|
|
p.result = result
|
|
|
|
return nil
|
|
}
|
|
|
|
func appendExtractionWarnings(result *models.AnalysisResult, files []ExtractedFile) {
|
|
if result == nil {
|
|
return
|
|
}
|
|
|
|
truncated := make([]string, 0)
|
|
for _, f := range files {
|
|
if !f.Truncated {
|
|
continue
|
|
}
|
|
if f.TruncatedMessage != "" {
|
|
truncated = append(truncated, fmt.Sprintf("%s: %s", f.Path, f.TruncatedMessage))
|
|
continue
|
|
}
|
|
truncated = append(truncated, fmt.Sprintf("%s: content was truncated due to size limit", f.Path))
|
|
}
|
|
|
|
if len(truncated) == 0 {
|
|
return
|
|
}
|
|
|
|
result.Events = append(result.Events, models.Event{
|
|
Timestamp: time.Now(),
|
|
Source: "LOGPile",
|
|
EventType: "Analysis Warning",
|
|
Severity: models.SeverityWarning,
|
|
Description: "Input data was too large; analysis is partial and may be incomplete",
|
|
RawData: strings.Join(truncated, "; "),
|
|
})
|
|
}
|
|
|
|
// Result returns the analysis result
|
|
func (p *BMCParser) Result() *models.AnalysisResult {
|
|
return p.result
|
|
}
|
|
|
|
// GetFiles returns all extracted files
|
|
func (p *BMCParser) GetFiles() []ExtractedFile {
|
|
return p.files
|
|
}
|
|
|
|
// DetectedVendor returns the detected vendor parser name
|
|
func (p *BMCParser) DetectedVendor() string {
|
|
if p.vendorParser != nil {
|
|
return p.vendorParser.Name()
|
|
}
|
|
return "unknown"
|
|
}
|