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/backendplugin/coreplugin/registry.go

275 lines
8.7 KiB

package coreplugin
import (
"context"
"errors"
"fmt"
"github.com/grafana/grafana-plugin-sdk-go/backend"
sdklog "github.com/grafana/grafana-plugin-sdk-go/backend/log"
sdktracing "github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/log"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor"
cloudmonitoring "github.com/grafana/grafana/pkg/tsdb/cloud-monitoring"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch"
"github.com/grafana/grafana/pkg/tsdb/elasticsearch"
postgres "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource"
pyroscope "github.com/grafana/grafana/pkg/tsdb/grafana-pyroscope-datasource"
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
"github.com/grafana/grafana/pkg/tsdb/grafanads"
"github.com/grafana/grafana/pkg/tsdb/graphite"
"github.com/grafana/grafana/pkg/tsdb/influxdb"
"github.com/grafana/grafana/pkg/tsdb/jaeger"
"github.com/grafana/grafana/pkg/tsdb/loki"
"github.com/grafana/grafana/pkg/tsdb/mssql"
"github.com/grafana/grafana/pkg/tsdb/mysql"
"github.com/grafana/grafana/pkg/tsdb/opentsdb"
"github.com/grafana/grafana/pkg/tsdb/parca"
"github.com/grafana/grafana/pkg/tsdb/prometheus"
"github.com/grafana/grafana/pkg/tsdb/tempo"
"github.com/grafana/grafana/pkg/tsdb/zipkin"
)
const (
CloudWatch = "cloudwatch"
CloudMonitoring = "stackdriver"
AzureMonitor = "grafana-azure-monitor-datasource"
Elasticsearch = "elasticsearch"
Graphite = "graphite"
InfluxDB = "influxdb"
Loki = "loki"
OpenTSDB = "opentsdb"
Prometheus = "prometheus"
Tempo = "tempo"
TestData = "grafana-testdata-datasource"
TestDataAlias = "testdata"
PostgreSQL = "grafana-postgresql-datasource"
MySQL = "mysql"
MSSQL = "mssql"
Grafana = "grafana"
Pyroscope = "grafana-pyroscope-datasource"
Parca = "parca"
Zipkin = "zipkin"
Jaeger = "jaeger"
)
func init() {
// Non-optimal global solution to replace plugin SDK default loggers for core plugins.
sdklog.DefaultLogger = &logWrapper{logger: log.New("plugin.coreplugin")}
backend.Logger = sdklog.DefaultLogger
backend.NewLoggerWith = func(args ...any) sdklog.Logger {
for i, arg := range args {
// Obtain logger name from args.
if s, ok := arg.(string); ok && s == "logger" {
l := &logWrapper{logger: log.New(args[i+1].(string))}
// new args slice without logger name and logger name value
if len(args) > 2 {
newArgs := make([]any, 0, len(args)-2)
newArgs = append(newArgs, args[:i]...)
newArgs = append(newArgs, args[i+2:]...)
return l.With(newArgs...)
}
return l
}
}
return sdklog.DefaultLogger
}
}
type Registry struct {
store map[string]backendplugin.PluginFactoryFunc
}
func NewRegistry(store map[string]backendplugin.PluginFactoryFunc) *Registry {
return &Registry{
store: store,
}
}
func ProvideCoreRegistry(tracer tracing.Tracer, am *azuremonitor.Service, cw *cloudwatch.CloudWatchService, cm *cloudmonitoring.Service,
es *elasticsearch.Service, grap *graphite.Service, idb *influxdb.Service, lk *loki.Service, otsdb *opentsdb.Service,
pr *prometheus.Service, t *tempo.Service, td *testdatasource.Service, pg *postgres.Service, my *mysql.Service,
ms *mssql.Service, graf *grafanads.Service, pyroscope *pyroscope.Service, parca *parca.Service, zipkin *zipkin.Service, jaeger *jaeger.Service) *Registry {
// Non-optimal global solution to replace plugin SDK default tracer for core plugins.
sdktracing.InitDefaultTracer(tracer)
return NewRegistry(map[string]backendplugin.PluginFactoryFunc{
CloudWatch: asBackendPlugin(cw.Executor),
CloudMonitoring: asBackendPlugin(cm),
AzureMonitor: asBackendPlugin(am),
Elasticsearch: asBackendPlugin(es),
Graphite: asBackendPlugin(grap),
InfluxDB: asBackendPlugin(idb),
Loki: asBackendPlugin(lk),
OpenTSDB: asBackendPlugin(otsdb),
Prometheus: asBackendPlugin(pr),
Tempo: asBackendPlugin(t),
TestData: asBackendPlugin(td),
PostgreSQL: asBackendPlugin(pg),
MySQL: asBackendPlugin(my),
MSSQL: asBackendPlugin(ms),
Grafana: asBackendPlugin(graf),
Pyroscope: asBackendPlugin(pyroscope),
Parca: asBackendPlugin(parca),
Zipkin: asBackendPlugin(zipkin),
Jaeger: asBackendPlugin(jaeger),
})
}
func (cr *Registry) Get(pluginID string) backendplugin.PluginFactoryFunc {
return cr.store[pluginID]
}
func (cr *Registry) BackendFactoryProvider() func(_ context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
return func(_ context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
if !p.IsCorePlugin() {
return nil
}
return cr.Get(p.ID)
}
}
func asBackendPlugin(svc any) backendplugin.PluginFactoryFunc {
opts := backend.ServeOpts{}
if queryHandler, ok := svc.(backend.QueryDataHandler); ok {
opts.QueryDataHandler = queryHandler
}
if resourceHandler, ok := svc.(backend.CallResourceHandler); ok {
opts.CallResourceHandler = resourceHandler
}
if streamHandler, ok := svc.(backend.StreamHandler); ok {
opts.StreamHandler = streamHandler
}
if healthHandler, ok := svc.(backend.CheckHealthHandler); ok {
opts.CheckHealthHandler = healthHandler
}
if storageHandler, ok := svc.(backend.AdmissionHandler); ok {
opts.AdmissionHandler = storageHandler
}
if opts.QueryDataHandler != nil || opts.CallResourceHandler != nil ||
opts.CheckHealthHandler != nil || opts.StreamHandler != nil {
return New(opts)
}
return nil
}
type logWrapper struct {
logger log.Logger
}
func (l *logWrapper) Debug(msg string, args ...any) {
l.logger.Debug(msg, args...)
}
func (l *logWrapper) Info(msg string, args ...any) {
l.logger.Info(msg, args...)
}
func (l *logWrapper) Warn(msg string, args ...any) {
l.logger.Warn(msg, args...)
}
func (l *logWrapper) Error(msg string, args ...any) {
l.logger.Error(msg, args...)
}
func (l *logWrapper) Level() sdklog.Level {
return sdklog.NoLevel
}
func (l *logWrapper) With(args ...any) sdklog.Logger {
return &logWrapper{
logger: l.logger.New(args...),
}
}
func (l *logWrapper) FromContext(ctx context.Context) sdklog.Logger {
return &logWrapper{
logger: l.logger.FromContext(ctx),
}
}
var ErrCorePluginNotFound = errors.New("core plugin not found")
// NewPlugin factory for creating and initializing a single core plugin.
// Note: cfg only needed for mssql connection pooling defaults.
func NewPlugin(pluginID string, cfg *setting.Cfg, httpClientProvider *httpclient.Provider, tracer tracing.Tracer, features featuremgmt.FeatureToggles) (*plugins.Plugin, error) {
jsonData := plugins.JSONData{
ID: pluginID,
AliasIDs: []string{},
}
var svc any
switch pluginID {
case TestData, TestDataAlias:
jsonData.ID = TestData
jsonData.AliasIDs = append(jsonData.AliasIDs, TestDataAlias)
svc = testdatasource.ProvideService()
case CloudWatch:
svc = cloudwatch.ProvideService(httpClientProvider).Executor
case CloudMonitoring:
svc = cloudmonitoring.ProvideService(httpClientProvider)
case AzureMonitor:
svc = azuremonitor.ProvideService(httpClientProvider)
case Elasticsearch:
svc = elasticsearch.ProvideService(httpClientProvider)
case Graphite:
svc = graphite.ProvideService(httpClientProvider, tracer)
case InfluxDB:
svc = influxdb.ProvideService(httpClientProvider, features)
case Loki:
svc = loki.ProvideService(httpClientProvider, tracer)
case OpenTSDB:
svc = opentsdb.ProvideService(httpClientProvider)
case Prometheus:
svc = prometheus.ProvideService(httpClientProvider)
case Tempo:
svc = tempo.ProvideService(httpClientProvider)
case PostgreSQL:
svc = postgres.ProvideService(cfg)
case MySQL:
svc = mysql.ProvideService()
case MSSQL:
svc = mssql.ProvideService(cfg)
case Pyroscope:
svc = pyroscope.ProvideService(httpClientProvider)
case Parca:
svc = parca.ProvideService(httpClientProvider)
case Zipkin:
svc = zipkin.ProvideService(httpClientProvider)
case Jaeger:
svc = jaeger.ProvideService(httpClientProvider)
default:
return nil, ErrCorePluginNotFound
}
p := plugins.Plugin{
JSONData: jsonData,
Class: plugins.ClassCore,
}
p.SetLogger(log.New(fmt.Sprintf("plugin.%s", p.ID)))
backendFactory := asBackendPlugin(svc)
if backendFactory == nil {
return nil, ErrCorePluginNotFound
}
bp, err := backendFactory(p.ID, p.Logger(), tracer, nil)
if err != nil {
return nil, err
}
p.RegisterClient(bp)
return &p, nil
}