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:
Syerikjan Kh
2024-10-10 20:30:56 -04:00
committed by GitHub
parent 27c44f4709
commit f8748f0724
13 changed files with 75 additions and 30 deletions

View File

@ -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)))),
},
}
}

View File

@ -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 },
)

View File

@ -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,
}