diff --git a/internal/builder/main.go b/internal/builder/main.go index 8a8ca6c012d..8cc9c9f784c 100644 --- a/internal/builder/main.go +++ b/internal/builder/main.go @@ -69,6 +69,14 @@ func Generate(cfg Config) error { "main.go", scaffold.Main, }, + { + "main_others.go", + scaffold.MainOthers, + }, + { + "main_windows.go", + scaffold.MainWindows, + }, // components.go { "components.go", diff --git a/internal/scaffold/main.go b/internal/scaffold/main.go index ddf60f52bbf..2002b0eca82 100644 --- a/internal/scaffold/main.go +++ b/internal/scaffold/main.go @@ -35,6 +35,7 @@ const Main = ` package main import ( + "fmt" "log" "go.opentelemetry.io/collector/component" @@ -53,14 +54,113 @@ func main() { Version: "{{ .Distribution.Version }}", } - app, err := service.New(service.CollectorSettings{BuildInfo: info, Factories: factories}) + if err := run(service.CollectorSettings{BuildInfo: info, Factories: factories}); err != nil { + log.Fatal(err) + } +} + +func runInteractive(params service.CollectorSettings) error { + app, err := service.New(params) if err != nil { - log.Fatalf("failed to construct the application: %v", err) + return fmt.Errorf("failed to construct the collector server: %w", err) } cmd := service.NewCommand(app) if err = cmd.Execute(); err != nil { - log.Fatalf("application run finished with error: %v", err) + log.Fatalf("collector server run finished with error: %v", err) + } + + return nil +} +` + +const MainOthers = ` +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !windows +// +build !windows + +package main + +import "go.opentelemetry.io/collector/service" + +func run(params service.CollectorSettings) error { + return runInteractive(params) +} +` + +const MainWindows = ` +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build windows +// +build windows + +package main + +import ( + "fmt" + "os" + + "go.opentelemetry.io/collector/service" + "golang.org/x/sys/windows/svc" +) + +func run(params service.CollectorSettings) error { + if useInteractiveMode, err := checkUseInteractiveMode(); err != nil { + return err + } else if useInteractiveMode { + return runInteractive(params) + } else { + return runService(params) + } +} + +func checkUseInteractiveMode() (bool, error) { + // If environment variable NO_WINDOWS_SERVICE is set with any value other + // than 0, use interactive mode instead of running as a service. This should + // be set in case running as a service is not possible or desired even + // though the current session is not detected to be interactive + if value, present := os.LookupEnv("NO_WINDOWS_SERVICE"); present && value != "0" { + return true, nil + } + + if isInteractiveSession, err := svc.IsAnInteractiveSession(); err != nil { + return false, fmt.Errorf("failed to determine if we are running in an interactive session %w", err) + } else { + return isInteractiveSession, nil } } + +func runService(params service.CollectorSettings) error { + // do not need to supply service name when startup is invoked through Service Control Manager directly + if err := svc.Run("", service.NewWindowsService(params)); err != nil { + return fmt.Errorf("failed to start collector server: %w", err) + } + + return nil +} `