mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 15:32:36 +08:00
ref: pass tracer to plugin factory func (#93701)
* ref: pass tracer to plugin factory func * fix: add tracer to coreplugin * test: fix test, generate wire * test: ignore trace field in loader_test * ref: pass tracer as dependency, don't store in plugin * ref: wrap tracer with tracer provider to satisfy WithTracerProvider * ref: use otel trace.Tracer type for tracer
This commit is contained in:
@ -3,7 +3,8 @@ package backendplugin
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// PluginFactoryFunc is a function type for creating a Plugin.
|
||||
type PluginFactoryFunc func(pluginID string, logger log.Logger, env func() []string) (Plugin, error)
|
||||
type PluginFactoryFunc func(pluginID string, logger log.Logger, tracer trace.Tracer, env func() []string) (Plugin, error)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
@ -24,7 +25,7 @@ type corePlugin struct {
|
||||
|
||||
// New returns a new backendplugin.PluginFactoryFunc for creating a core (built-in) backendplugin.Plugin.
|
||||
func New(opts backend.ServeOpts) backendplugin.PluginFactoryFunc {
|
||||
return func(pluginID string, logger log.Logger, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return func(pluginID string, logger log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return &corePlugin{
|
||||
pluginID: pluginID,
|
||||
logger: logger,
|
||||
|
@ -8,13 +8,14 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCorePlugin(t *testing.T) {
|
||||
t.Run("New core plugin with empty opts should return expected values", func(t *testing.T) {
|
||||
factory := coreplugin.New(backend.ServeOpts{})
|
||||
p, err := factory("plugin", log.New("test"), nil)
|
||||
p, err := factory("plugin", log.New("test"), fakes.InitializeNoopTracerForTest(), nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
require.NoError(t, p.Start(context.Background()))
|
||||
@ -47,7 +48,7 @@ func TestCorePlugin(t *testing.T) {
|
||||
return nil
|
||||
}),
|
||||
})
|
||||
p, err := factory("plugin", log.New("test"), nil)
|
||||
p, err := factory("plugin", log.New("test"), fakes.InitializeNoopTracerForTest(), nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, p)
|
||||
require.NoError(t, p.Start(context.Background()))
|
||||
|
@ -254,7 +254,7 @@ func NewPlugin(pluginID string, cfg *setting.Cfg, httpClientProvider *httpclient
|
||||
if backendFactory == nil {
|
||||
return nil, ErrCorePluginNotFound
|
||||
}
|
||||
bp, err := backendFactory(p.ID, p.Logger(), nil)
|
||||
bp, err := backendFactory(p.ID, p.Logger(), tracer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
|
||||
goplugin "github.com/hashicorp/go-plugin"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
trace "go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
@ -40,7 +42,20 @@ var pluginSet = map[int]goplugin.PluginSet{
|
||||
},
|
||||
}
|
||||
|
||||
func newClientConfig(executablePath string, args []string, env []string, skipHostEnvVars bool, logger log.Logger,
|
||||
type clientTracerProvider struct {
|
||||
tracer trace.Tracer
|
||||
embedded.TracerProvider
|
||||
}
|
||||
|
||||
func (ctp *clientTracerProvider) Tracer(instrumentationName string, opts ...trace.TracerOption) trace.Tracer {
|
||||
return ctp.tracer
|
||||
}
|
||||
|
||||
func newClientTracerProvider(tracer trace.Tracer) trace.TracerProvider {
|
||||
return &clientTracerProvider{tracer: tracer}
|
||||
}
|
||||
|
||||
func newClientConfig(executablePath string, args []string, env []string, skipHostEnvVars bool, logger log.Logger, tracer trace.Tracer,
|
||||
versionedPlugins map[int]goplugin.PluginSet) *goplugin.ClientConfig {
|
||||
// We can ignore gosec G201 here, since the dynamic part of executablePath comes from the plugin definition
|
||||
// nolint:gosec
|
||||
@ -55,7 +70,13 @@ func newClientConfig(executablePath string, args []string, env []string, skipHos
|
||||
Logger: logWrapper{Logger: logger},
|
||||
AllowedProtocols: []goplugin.Protocol{goplugin.ProtocolGRPC},
|
||||
GRPCDialOptions: []grpc.DialOption{
|
||||
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
|
||||
// https://github.com/grafana/app-platform-wg/issues/140
|
||||
// external plugins are loaded before k8s API server
|
||||
// configures the tracing service thus failing to
|
||||
// record trace span in the middleware.
|
||||
// With code below we are passing the same tracer that k8s API server
|
||||
// uses so that middleware is configured with tracer.
|
||||
grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(newClientTracerProvider(tracer)))),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
trace "go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
|
||||
@ -44,6 +45,7 @@ type ProtoClientOpts struct {
|
||||
ExecutableArgs []string
|
||||
Env []string
|
||||
Logger log.Logger
|
||||
Tracer trace.Tracer
|
||||
}
|
||||
|
||||
func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) {
|
||||
@ -56,6 +58,7 @@ func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) {
|
||||
versionedPlugins: pluginSet,
|
||||
},
|
||||
opts.Logger,
|
||||
opts.Tracer,
|
||||
func() []string { return opts.Env },
|
||||
)
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
trace "go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/process"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@ -37,17 +38,17 @@ const (
|
||||
|
||||
// newPlugin allocates and returns a new gRPC (external) backendplugin.Plugin.
|
||||
func newPlugin(descriptor PluginDescriptor) backendplugin.PluginFactoryFunc {
|
||||
return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) {
|
||||
return newGrpcPlugin(descriptor, logger, env), nil
|
||||
return func(pluginID string, logger log.Logger, tracer trace.Tracer, env func() []string) (backendplugin.Plugin, error) {
|
||||
return newGrpcPlugin(descriptor, logger, tracer, env), nil
|
||||
}
|
||||
}
|
||||
|
||||
func newGrpcPlugin(descriptor PluginDescriptor, logger log.Logger, env func() []string) *grpcPlugin {
|
||||
func newGrpcPlugin(descriptor PluginDescriptor, logger log.Logger, tracer trace.Tracer, env func() []string) *grpcPlugin {
|
||||
return &grpcPlugin{
|
||||
descriptor: descriptor,
|
||||
logger: logger,
|
||||
clientFactory: func() *plugin.Client {
|
||||
return plugin.NewClient(newClientConfig(descriptor.executablePath, descriptor.executableArgs, env(), descriptor.skipHostEnvVars, logger, descriptor.versionedPlugins))
|
||||
return plugin.NewClient(newClientConfig(descriptor.executablePath, descriptor.executableArgs, env(), descriptor.skipHostEnvVars, logger, tracer, descriptor.versionedPlugins))
|
||||
},
|
||||
state: pluginStateNotStarted,
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/auth"
|
||||
@ -267,6 +269,14 @@ func (r *FakePluginRepo) PluginVersion(ctx context.Context, pluginID, version st
|
||||
return repo.VersionData{}, nil
|
||||
}
|
||||
|
||||
type fakeTracerProvider struct {
|
||||
noop.TracerProvider
|
||||
}
|
||||
|
||||
func InitializeNoopTracerForTest() trace.Tracer {
|
||||
return fakeTracerProvider{}.Tracer("test")
|
||||
}
|
||||
|
||||
type FakePluginStorage struct {
|
||||
ExtractFunc func(_ context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error)
|
||||
}
|
||||
@ -340,7 +350,7 @@ func NewFakeBackendProcessProvider() *FakeBackendProcessProvider {
|
||||
}
|
||||
f.BackendFactoryFunc = func(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
|
||||
f.Requested[p.ID]++
|
||||
return func(pluginID string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return func(pluginID string, _ log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
|
||||
f.Invoked[pluginID]++
|
||||
return &FakePluginClient{}, nil
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/plugins/log"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/process"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/registry"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// BackendClientInit implements an InitializeFunc for initializing a backend plugin process.
|
||||
@ -21,20 +22,22 @@ type BackendClientInit struct {
|
||||
envVarProvider envvars.Provider
|
||||
backendProvider plugins.BackendFactoryProvider
|
||||
log log.Logger
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
// BackendClientInitStep returns a new InitializeFunc for registering a backend plugin process.
|
||||
func BackendClientInitStep(envVarProvider envvars.Provider,
|
||||
backendProvider plugins.BackendFactoryProvider) InitializeFunc {
|
||||
return newBackendProcessRegistration(envVarProvider, backendProvider).Initialize
|
||||
backendProvider plugins.BackendFactoryProvider, tracer trace.Tracer) InitializeFunc {
|
||||
return newBackendProcessRegistration(envVarProvider, backendProvider, tracer).Initialize
|
||||
}
|
||||
|
||||
func newBackendProcessRegistration(envVarProvider envvars.Provider,
|
||||
backendProvider plugins.BackendFactoryProvider) *BackendClientInit {
|
||||
backendProvider plugins.BackendFactoryProvider, tracer trace.Tracer) *BackendClientInit {
|
||||
return &BackendClientInit{
|
||||
backendProvider: backendProvider,
|
||||
envVarProvider: envVarProvider,
|
||||
log: log.New("plugins.backend.registration"),
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +52,7 @@ func (b *BackendClientInit) Initialize(ctx context.Context, p *plugins.Plugin) (
|
||||
// this will ensure that the env variables are calculated every time a plugin is started
|
||||
envFunc := func() []string { return b.envVarProvider.PluginEnvVars(ctx, p) }
|
||||
|
||||
if backendClient, err := backendFactory(p.ID, p.Logger(), envFunc); err != nil {
|
||||
if backendClient, err := backendFactory(p.ID, p.Logger(), b.tracer, envFunc); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
p.RegisterClient(backendClient)
|
||||
|
@ -4,11 +4,12 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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/plugins/manager/fakes"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func TestInitializer_Initialize(t *testing.T) {
|
||||
@ -28,7 +29,7 @@ func TestInitializer_Initialize(t *testing.T) {
|
||||
Class: plugins.ClassCore,
|
||||
}
|
||||
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
|
||||
|
||||
var err error
|
||||
p, err = stepFunc(context.Background(), p)
|
||||
@ -52,7 +53,7 @@ func TestInitializer_Initialize(t *testing.T) {
|
||||
Class: plugins.ClassExternal,
|
||||
}
|
||||
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
|
||||
|
||||
var err error
|
||||
p, err = stepFunc(context.Background(), p)
|
||||
@ -76,7 +77,7 @@ func TestInitializer_Initialize(t *testing.T) {
|
||||
Class: plugins.ClassExternal,
|
||||
}
|
||||
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p})
|
||||
stepFunc := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{plugin: p}, fakes.InitializeNoopTracerForTest())
|
||||
|
||||
var err error
|
||||
p, err = stepFunc(context.Background(), p)
|
||||
@ -96,7 +97,7 @@ func TestInitializer_Initialize(t *testing.T) {
|
||||
|
||||
i := BackendClientInitStep(&fakeEnvVarsProvider{}, &fakeBackendProvider{
|
||||
plugin: p,
|
||||
})
|
||||
}, fakes.InitializeNoopTracerForTest())
|
||||
|
||||
var err error
|
||||
p, err = i(context.Background(), p)
|
||||
@ -115,7 +116,7 @@ type fakeBackendProvider struct {
|
||||
}
|
||||
|
||||
func (f *fakeBackendProvider) BackendFactory(_ context.Context, _ *plugins.Plugin) backendplugin.PluginFactoryFunc {
|
||||
return func(_ string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return func(_ string, _ log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return f.plugin, nil
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@ -584,7 +585,7 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) {
|
||||
|
||||
backendFactoryProvider := fakes.NewFakeBackendProcessProvider()
|
||||
backendFactoryProvider.BackendFactoryFunc = func(ctx context.Context, plugin *plugins.Plugin) backendplugin.PluginFactoryFunc {
|
||||
return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) {
|
||||
return func(pluginID string, logger log.Logger, tracer trace.Tracer, env func() []string) (backendplugin.Plugin, error) {
|
||||
require.Equal(t, "grafana-test-datasource", pluginID)
|
||||
return &fakes.FakeBackendPlugin{}, nil
|
||||
}
|
||||
@ -1133,7 +1134,7 @@ func TestLoader_Load_SkipUninitializedPlugins(t *testing.T) {
|
||||
procPrvdr := fakes.NewFakeBackendProcessProvider()
|
||||
// Cause an initialization error
|
||||
procPrvdr.BackendFactoryFunc = func(ctx context.Context, p *plugins.Plugin) backendplugin.PluginFactoryFunc {
|
||||
return func(pluginID string, _ log.Logger, _ func() []string) (backendplugin.Plugin, error) {
|
||||
return func(pluginID string, _ log.Logger, _ trace.Tracer, _ func() []string) (backendplugin.Plugin, error) {
|
||||
if pluginID == "test-datasource" {
|
||||
return nil, errors.New("failed to initialize")
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func ProvideInitializationStage(cfg *config.PluginManagementCfg, pr registry.Ser
|
||||
return initialization.New(cfg, initialization.Opts{
|
||||
InitializeFuncs: []initialization.InitializeFunc{
|
||||
ExternalServiceRegistrationStep(cfg, externalServiceRegistry, tracer),
|
||||
initialization.BackendClientInitStep(pluginEnvProvider, bp),
|
||||
initialization.BackendClientInitStep(pluginEnvProvider, bp, tracer),
|
||||
initialization.BackendProcessStartStep(pm),
|
||||
RegisterPluginRolesStep(roleRegistry),
|
||||
RegisterActionSetsStep(actionSetRegistry),
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/provider"
|
||||
@ -22,11 +23,12 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pipeline"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs"
|
||||
"github.com/grafana/grafana/pkg/services/rendering"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func ProvideService(cfg *config.PluginManagementCfg, pluginEnvProvider envvars.Provider,
|
||||
registry registry.Service) (*Manager, error) {
|
||||
l, err := createLoader(cfg, pluginEnvProvider, registry)
|
||||
registry registry.Service, tracer tracing.Tracer) (*Manager, error) {
|
||||
l, err := createLoader(cfg, pluginEnvProvider, registry, tracer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -105,7 +107,7 @@ func (m *Manager) Renderer(ctx context.Context) (rendering.Plugin, bool) {
|
||||
}
|
||||
|
||||
func createLoader(cfg *config.PluginManagementCfg, pluginEnvProvider envvars.Provider,
|
||||
pr registry.Service) (loader.Service, error) {
|
||||
pr registry.Service, tracer trace.Tracer) (loader.Service, error) {
|
||||
d := discovery.New(cfg, discovery.Opts{
|
||||
FindFilterFuncs: []discovery.FindFilterFunc{
|
||||
discovery.NewPermittedPluginTypesFilterStep([]plugins.Type{plugins.TypeRenderer}),
|
||||
@ -124,7 +126,7 @@ func createLoader(cfg *config.PluginManagementCfg, pluginEnvProvider envvars.Pro
|
||||
})
|
||||
i := initialization.New(cfg, initialization.Opts{
|
||||
InitializeFuncs: []initialization.InitializeFunc{
|
||||
initialization.BackendClientInitStep(pluginEnvProvider, provider.New(provider.RendererProvider)),
|
||||
initialization.BackendClientInitStep(pluginEnvProvider, provider.New(provider.RendererProvider), tracer),
|
||||
initialization.PluginRegistrationStep(pr),
|
||||
},
|
||||
})
|
||||
|
Reference in New Issue
Block a user