Add DiagnosticsWriter interface to abstract over diagnostics output implementation

This commit is contained in:
Michael B. Gale
2026-01-25 14:14:27 +00:00
parent f837d90060
commit fafc2ddc0b

View File

@@ -3,7 +3,7 @@ package diagnostics
import (
"encoding/json"
"fmt"
"log"
"log/slog"
"os"
"strings"
"time"
@@ -56,19 +56,62 @@ type diagnostic struct {
var diagnosticsEmitted, diagnosticsLimit uint = 0, 100
var noDiagnosticDirPrinted bool = false
func emitDiagnostic(sourceid, sourcename, markdownMessage string, severity diagnosticSeverity, visibility *visibilityStruct, location *locationStruct) {
type DiagnosticsWriter interface {
WriteDiagnostic(d diagnostic)
}
type FileDiagnosticsWriter struct {
diagnosticDir string
}
func (writer *FileDiagnosticsWriter) WriteDiagnostic(d diagnostic) {
content, err := json.Marshal(d)
if err != nil {
slog.Error("Failed to encode diagnostic as JSON", slog.Any("err", err))
return
}
targetFile, err := os.CreateTemp(writer.diagnosticDir, "go-extractor.*.json")
if err != nil {
slog.Error("Failed to create diagnostic file", slog.Any("err", err))
return
}
defer func() {
if err := targetFile.Close(); err != nil {
slog.Error("Failed to close diagnostic file", slog.Any("err", err))
}
}()
_, err = targetFile.Write(content)
if err != nil {
slog.Error("Failed to write to diagnostic file", slog.Any("err", err))
}
}
var DefaultWriter *FileDiagnosticsWriter = nil
func NewFileDiagnosticsWriter() *FileDiagnosticsWriter {
diagnosticDir := os.Getenv("CODEQL_EXTRACTOR_GO_DIAGNOSTIC_DIR")
if diagnosticDir == "" {
if !noDiagnosticDirPrinted {
slog.Warn("No diagnostic directory set, so not emitting diagnostics")
noDiagnosticDirPrinted = true
}
return nil
}
return &FileDiagnosticsWriter{diagnosticDir}
}
func init() {
DefaultWriter = NewFileDiagnosticsWriter()
}
// Emits a diagnostic using the specified `DiagnosticsWriter`.
func emitDiagnosticTo(writer DiagnosticsWriter, sourceid, sourcename, markdownMessage string, severity diagnosticSeverity, visibility *visibilityStruct, location *locationStruct) {
if diagnosticsEmitted < diagnosticsLimit {
diagnosticsEmitted += 1
diagnosticDir := os.Getenv("CODEQL_EXTRACTOR_GO_DIAGNOSTIC_DIR")
if diagnosticDir == "" {
if !noDiagnosticDirPrinted {
log.Println("No diagnostic directory set, so not emitting diagnostic")
noDiagnosticDirPrinted = true
}
return
}
timestamp := time.Now().UTC().Format("2006-01-02T15:04:05.000") + "Z"
var d diagnostic
@@ -93,33 +136,18 @@ func emitDiagnostic(sourceid, sourcename, markdownMessage string, severity diagn
}
}
content, err := json.Marshal(d)
if err != nil {
log.Println(err)
return
}
targetFile, err := os.CreateTemp(diagnosticDir, "go-extractor.*.json")
if err != nil {
log.Println("Failed to create diagnostic file: ")
log.Println(err)
return
}
defer func() {
if err := targetFile.Close(); err != nil {
log.Println("Failed to close diagnostic file:")
log.Println(err)
}
}()
_, err = targetFile.Write(content)
if err != nil {
log.Println("Failed to write to diagnostic file: ")
log.Println(err)
}
writer.WriteDiagnostic(d)
}
}
// Emits a diagnostic using the default `DiagnosticsWriter`.
func emitDiagnostic(sourceid, sourcename, markdownMessage string, severity diagnosticSeverity, visibility *visibilityStruct, location *locationStruct) {
if DefaultWriter == nil {
return
}
emitDiagnosticTo(DefaultWriter, sourceid, sourcename, markdownMessage, severity, visibility, location)
}
func EmitPackageDifferentOSArchitecture(pkgPath string) {
emitDiagnostic(
"go/autobuilder/package-different-os-architecture",