Transport structured diagnostics through the pipeline
This commit is contained in:
107
internal/framework/pipeline/diagnostics.go
Normal file
107
internal/framework/pipeline/diagnostics.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
|
||||
frameworkdiagnostics "gitea.maximumdirect.net/eric/notarius/internal/framework/diagnostics"
|
||||
)
|
||||
|
||||
func terminalDiagnosticGroups(terminal producerAttemptTerminal, origin contracts.DiagnosticOrigin, chunk *source.Chunk) ([]contracts.DiagnosticGroup, error) {
|
||||
groups, err := promoteProducerDiagnostics(terminal.Diagnostics, origin, chunk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, record := range terminal.Validation.Diagnostics() {
|
||||
validatorOrigin := origin
|
||||
validatorOrigin.ValidatorKey = record.validatorName
|
||||
promoted, err := promoteProducerDiagnostics([]contracts.ProducerDiagnostic{record.diagnostic}, validatorOrigin, chunk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("validator %q diagnostic: %w", record.validatorName, err)
|
||||
}
|
||||
groups = append(groups, promoted...)
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func promoteProducerDiagnostics(diagnostics []contracts.ProducerDiagnostic, origin contracts.DiagnosticOrigin, chunk *source.Chunk) ([]contracts.DiagnosticGroup, error) {
|
||||
if err := contracts.ValidateProducerDiagnostics(diagnostics); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(diagnostics) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
groups := make([]contracts.DiagnosticGroup, len(diagnostics))
|
||||
for index, diagnostic := range diagnostics {
|
||||
group := contracts.DiagnosticGroup{
|
||||
Disposition: diagnostic.Disposition,
|
||||
Category: diagnostic.Category,
|
||||
ReasonCode: diagnostic.ReasonCode,
|
||||
Origin: origin,
|
||||
OccurrenceCount: diagnostic.OccurrenceCount,
|
||||
Samples: cloneDiagnosticSamples(diagnostic.Samples, chunk),
|
||||
OmittedSampleCount: diagnostic.OmittedSampleCount,
|
||||
}
|
||||
if err := group.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups[index] = group
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func cloneDiagnosticSamples(samples []contracts.DiagnosticSample, chunk *source.Chunk) []contracts.DiagnosticSample {
|
||||
if len(samples) == 0 {
|
||||
return nil
|
||||
}
|
||||
cloned := make([]contracts.DiagnosticSample, len(samples))
|
||||
for index, sample := range samples {
|
||||
if chunk != nil {
|
||||
chunkIndex := chunk.Index
|
||||
sample.ChunkID = chunk.ID
|
||||
sample.ChunkIndex = &chunkIndex
|
||||
} else if sample.ChunkIndex != nil {
|
||||
chunkIndex := *sample.ChunkIndex
|
||||
sample.ChunkIndex = &chunkIndex
|
||||
}
|
||||
cloned[index] = sample
|
||||
}
|
||||
return cloned
|
||||
}
|
||||
|
||||
func appendDiagnosticGroups(output *RunOutput, groups []contracts.DiagnosticGroup) {
|
||||
if output == nil || len(groups) == 0 {
|
||||
return
|
||||
}
|
||||
cloned := contracts.CloneDiagnosticCollection(contracts.DiagnosticCollection{Groups: groups}).Groups
|
||||
output.diagnosticGroups = append(output.diagnosticGroups, cloned...)
|
||||
seen := make(map[contracts.Warning]struct{}, len(output.Warnings))
|
||||
for _, warning := range output.Warnings {
|
||||
seen[warning] = struct{}{}
|
||||
}
|
||||
for _, group := range cloned {
|
||||
for _, sample := range group.Samples {
|
||||
warning := contracts.Warning{Scope: sample.Scope, ReasonCode: group.ReasonCode, Message: sample.Message}
|
||||
if _, exists := seen[warning]; exists {
|
||||
continue
|
||||
}
|
||||
output.Warnings = append(output.Warnings, warning)
|
||||
seen[warning] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func finalizeDiagnostics(output *RunOutput) error {
|
||||
if output == nil {
|
||||
return nil
|
||||
}
|
||||
aggregator := frameworkdiagnostics.Aggregator{}
|
||||
for _, group := range output.diagnosticGroups {
|
||||
if err := aggregator.Add(group); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
output.Diagnostics = aggregator.Collection()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user