The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/plugins/manager/loader/loader.go

131 lines
3.9 KiB

package loader
import (
"context"
"errors"
"sort"
"strings"
"time"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/termination"
"github.com/grafana/grafana/pkg/plugins/manager/pipeline/validation"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
)
type Loader struct {
discovery discovery.Discoverer
bootstrap bootstrap.Bootstrapper
initializer initialization.Initializer
termination termination.Terminator
validation validation.Validator
errorTracker pluginerrs.ErrorTracker
log log.Logger
}
func New(discovery discovery.Discoverer, bootstrap bootstrap.Bootstrapper, validation validation.Validator,
initializer initialization.Initializer, termination termination.Terminator, errorTracker pluginerrs.ErrorTracker) *Loader {
return &Loader{
discovery: discovery,
bootstrap: bootstrap,
validation: validation,
initializer: initializer,
termination: termination,
errorTracker: errorTracker,
log: log.New("plugin.loader"),
}
}
func (l *Loader) recordError(ctx context.Context, p *plugins.Plugin, err error) {
var pErr *plugins.Error
if errors.As(err, &pErr) {
l.errorTracker.Record(ctx, pErr)
return
}
l.errorTracker.Record(ctx, &plugins.Error{
PluginID: p.ID,
ErrorCode: plugins.ErrorCode(err.Error()),
})
}
func (l *Loader) Load(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) {
end := l.instrumentLoad(ctx, src)
discoveredPlugins, err := l.discovery.Discover(ctx, src)
if err != nil {
return nil, err
}
bootstrappedPlugins := []*plugins.Plugin{}
for _, foundBundle := range discoveredPlugins {
bootstrappedPlugin, err := l.bootstrap.Bootstrap(ctx, src, foundBundle)
if err != nil {
l.errorTracker.Record(ctx, &plugins.Error{
PluginID: foundBundle.Primary.JSONData.ID,
ErrorCode: plugins.ErrorCode(err.Error()),
})
continue
}
bootstrappedPlugins = append(bootstrappedPlugins, bootstrappedPlugin...)
}
validatedPlugins := []*plugins.Plugin{}
for _, bootstrappedPlugin := range bootstrappedPlugins {
err := l.validation.Validate(ctx, bootstrappedPlugin)
if err != nil {
l.recordError(ctx, bootstrappedPlugin, err)
continue
}
validatedPlugins = append(validatedPlugins, bootstrappedPlugin)
}
initializedPlugins := []*plugins.Plugin{}
for _, validatedPlugin := range validatedPlugins {
initializedPlugin, err := l.initializer.Initialize(ctx, validatedPlugin)
if err != nil {
l.recordError(ctx, validatedPlugin, err)
continue
}
initializedPlugins = append(initializedPlugins, initializedPlugin)
}
// Clean errors from registry for initialized plugins
for _, p := range initializedPlugins {
l.errorTracker.Clear(ctx, p.ID)
}
end(initializedPlugins)
return initializedPlugins, nil
}
func (l *Loader) Unload(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) {
return l.termination.Terminate(ctx, p)
}
func (l *Loader) instrumentLoad(ctx context.Context, src plugins.PluginSource) func([]*plugins.Plugin) {
start := time.Now()
sourceLogger := l.log.New("source", src.PluginClass(ctx)).FromContext(ctx)
sourceLogger.Debug("Loading plugin source...")
return func(logger log.Logger, start time.Time) func([]*plugins.Plugin) {
return func(plugins []*plugins.Plugin) {
if len(plugins) == 0 {
logger.Debug("Plugin source loaded, though no plugins were found")
return
}
names := make([]string, len(plugins))
for i, p := range plugins {
names[i] = p.ID
}
sort.Strings(names)
pluginsStr := strings.Join(names, ", ")
logger.Debug("Plugin source loaded", "plugins", pluginsStr, "duration", time.Since(start))
}
}(sourceLogger, start)
}