diff --git a/buildengine/testdata/type_registry_main.go b/buildengine/testdata/type_registry_main.go index 2a051f0718..61a8d30ab8 100644 --- a/buildengine/testdata/type_registry_main.go +++ b/buildengine/testdata/type_registry_main.go @@ -35,7 +35,7 @@ func init() { } func main() { - verbConstructor := server.NewUserVerbServer("other", + verbConstructor := server.NewUserVerbServer("ftl", "other", server.HandleCall(other.Echo), ) plugin.Start(context.Background(), "other", verbConstructor, ftlv1connect.VerbServiceName, ftlv1connect.NewVerbServiceHandler) diff --git a/cmd/ftl-controller/main.go b/cmd/ftl-controller/main.go index d4ef85f8a4..53ca9bc530 100644 --- a/cmd/ftl-controller/main.go +++ b/cmd/ftl-controller/main.go @@ -47,7 +47,7 @@ func main() { kctx.FatalIfErrorf(err, "failed to create encryptors") ctx := log.ContextWithLogger(context.Background(), log.Configure(os.Stderr, cli.LogConfig)) - err = observability.Init(ctx, "ftl-controller", ftl.Version, cli.ObservabilityConfig) + err = observability.Init(ctx, false, "", "ftl-controller", ftl.Version, cli.ObservabilityConfig) kctx.FatalIfErrorf(err, "failed to initialize observability") // The FTL controller currently only supports DB as a configuration provider/resolver. diff --git a/cmd/ftl-runner/main.go b/cmd/ftl-runner/main.go index 8f088c73cb..1e9b784921 100644 --- a/cmd/ftl-runner/main.go +++ b/cmd/ftl-runner/main.go @@ -44,7 +44,7 @@ and route to user code. }) logger := log.Configure(os.Stderr, cli.LogConfig) ctx := log.ContextWithLogger(context.Background(), logger) - err = observability.Init(ctx, "ftl-runner", ftl.Version, cli.ObservabilityConfig) + err = observability.Init(ctx, false, "", "ftl-runner", ftl.Version, cli.ObservabilityConfig) kctx.FatalIfErrorf(err, "failed to initialize observability") err = runner.Start(ctx, cli.RunnerConfig) kctx.FatalIfErrorf(err) diff --git a/cmd/ftl/cmd_serve.go b/cmd/ftl/cmd_serve.go index 69c1644859..ef6037cef5 100644 --- a/cmd/ftl/cmd_serve.go +++ b/cmd/ftl/cmd_serve.go @@ -93,7 +93,7 @@ func (s *serveCmd) run(ctx context.Context, projConfig projectconfig.Config, ini return err } - err = observability.Init(ctx, "ftl-serve", ftl.Version, s.ObservabilityConfig) + err = observability.Init(ctx, false, "", "ftl-serve", ftl.Version, s.ObservabilityConfig) if err != nil { return fmt.Errorf("observability init failed: %w", err) } diff --git a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl index 32c27567d1..952d50a0e3 100644 --- a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl +++ b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl @@ -40,7 +40,7 @@ func init() { {{- end}} func main() { - verbConstructor := server.NewUserVerbServer("{{.Name}}", + verbConstructor := server.NewUserVerbServer("{{.ProjectName}}", "{{.Name}}", {{- range .Verbs}} {{- if and .HasRequest .HasResponse}} server.HandleCall({{.Package}}.{{.Name}}), diff --git a/go-runtime/compile/build.go b/go-runtime/compile/build.go index 8ae7646659..f0d1e60382 100644 --- a/go-runtime/compile/build.go +++ b/go-runtime/compile/build.go @@ -27,6 +27,7 @@ import ( schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema" "github.com/TBD54566975/ftl/backend/schema" "github.com/TBD54566975/ftl/common/moduleconfig" + "github.com/TBD54566975/ftl/common/projectconfig" extract "github.com/TBD54566975/ftl/go-runtime/schema" "github.com/TBD54566975/ftl/internal" "github.com/TBD54566975/ftl/internal/exec" @@ -59,6 +60,7 @@ type mainModuleContext struct { GoVersion string FTLVersion string Name string + ProjectName string SharedModulesPaths []string Verbs []goVerb Replacements []*modfile.Replace @@ -123,6 +125,15 @@ func Build(ctx context.Context, projectRootDir, moduleDir string, sch *schema.Sc ftlVersion = ftl.Version } + projectName := "" + if pcpath, ok := projectconfig.DefaultConfigPath().Get(); ok { + pc, err := projectconfig.Load(ctx, pcpath) + if err != nil { + return fmt.Errorf("failed to load project config: %w", err) + } + projectName = pc.Name + } + config, err := moduleconfig.LoadModuleConfig(moduleDir) if err != nil { return fmt.Errorf("failed to load module config: %w", err) @@ -203,6 +214,7 @@ func Build(ctx context.Context, projectRootDir, moduleDir string, sch *schema.Sc GoVersion: goModVersion, FTLVersion: ftlVersion, Name: result.Module.Name, + ProjectName: projectName, SharedModulesPaths: sharedModulesPaths, Verbs: goVerbs, Replacements: replacements, diff --git a/go-runtime/server/server.go b/go-runtime/server/server.go index 367ca687c1..25c73835d5 100644 --- a/go-runtime/server/server.go +++ b/go-runtime/server/server.go @@ -31,7 +31,7 @@ type UserVerbConfig struct { // NewUserVerbServer starts a new code-generated drive for user Verbs. // // This function is intended to be used by the code generator. -func NewUserVerbServer(moduleName string, handlers ...Handler) plugin.Constructor[ftlv1connect.VerbServiceHandler, UserVerbConfig] { +func NewUserVerbServer(projectName string, moduleName string, handlers ...Handler) plugin.Constructor[ftlv1connect.VerbServiceHandler, UserVerbConfig] { return func(ctx context.Context, uc UserVerbConfig) (context.Context, ftlv1connect.VerbServiceHandler, error) { verbServiceClient := rpc.Dial(ftlv1connect.NewVerbServiceClient, uc.FTLEndpoint.String(), log.Error) ctx = rpc.ContextWithClient(ctx, verbServiceClient) @@ -45,7 +45,7 @@ func NewUserVerbServer(moduleName string, handlers ...Handler) plugin.Constructo ctx = dynamicCtx.ApplyToContext(ctx) ctx = internal.WithContext(ctx, internal.New(dynamicCtx)) - err = observability.Init(ctx, moduleName, "HEAD", uc.ObservabilityConfig) + err = observability.Init(ctx, true, projectName, moduleName, "HEAD", uc.ObservabilityConfig) if err != nil { return nil, nil, fmt.Errorf("could not initialize metrics: %w", err) } diff --git a/internal/observability/client.go b/internal/observability/client.go index 0fcd9531ab..0135663bef 100644 --- a/internal/observability/client.go +++ b/internal/observability/client.go @@ -7,6 +7,7 @@ import ( "strings" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/propagation" @@ -34,7 +35,7 @@ type Config struct { ExportOTEL ExportOTELFlag `help:"Export observability data to OTEL." env:"OTEL_EXPORTER_OTLP_ENDPOINT"` } -func Init(ctx context.Context, serviceName, serviceVersion string, config Config) error { +func Init(ctx context.Context, isUserService bool, projectName, serviceName, serviceVersion string, config Config) error { logger := log.FromContext(ctx) if !config.ExportOTEL { logger.Tracef("OTEL export is disabled, set OTEL_EXPORTER_OTLP_ENDPOINT to enable") @@ -52,6 +53,8 @@ func Init(ctx context.Context, serviceName, serviceVersion string, config Config schemaURL, semconv.ServiceName(serviceName), semconv.ServiceVersion(serviceVersion), + attribute.Bool("ftl.is_user_service", isUserService), + attribute.String("ftl.project_name", projectName), )) if err != nil { return fmt.Errorf("failed to create OTEL resource: %w", err)