This repository has been archived by the owner on Oct 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Facilitate External Agent Compilation (#1118)
- Move `internal/` to `pkg/` - Commit generated code - Make agent main code importable Co-authored-by: Ben Keith <[email protected]>
- Loading branch information
1 parent
5e854d2
commit c295133
Showing
808 changed files
with
18,219 additions
and
1,571 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
package agentmain | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"os" | ||
"os/signal" | ||
"runtime" | ||
"strings" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/sirupsen/logrus" | ||
log "github.com/sirupsen/logrus" | ||
|
||
"github.com/signalfx/signalfx-agent/pkg/core" | ||
"github.com/signalfx/signalfx-agent/pkg/core/common/constants" | ||
"github.com/signalfx/signalfx-agent/pkg/selfdescribe" | ||
|
||
prefixed "github.com/x-cray/logrus-prefixed-formatter" | ||
) | ||
|
||
func init() { | ||
log.SetFormatter(&prefixed.TextFormatter{}) | ||
log.SetLevel(log.InfoLevel) | ||
log.SetOutput(os.Stdout) | ||
} | ||
|
||
const windowsOS = "windows" | ||
|
||
func getDefaultConfigPath() string { | ||
if runtime.GOOS == windowsOS { | ||
return "\\ProgramData\\SignalFxAgent\\agent.yaml" | ||
} | ||
return "/etc/signalfx/agent.yaml" | ||
} | ||
|
||
// Set an envvar with the agent's version so that plugins can have easy access | ||
// to it (e.g. metadata plugin). | ||
func setVersionEnvvar() { | ||
os.Setenv(constants.AgentVersionEnvVar, constants.Version) | ||
} | ||
|
||
// Set an envvar with the collectd version so that plugins have easy access to it | ||
func setCollectdVersionEnvvar() { | ||
os.Setenv(constants.CollectdVersionEnvVar, constants.CollectdVersion) | ||
} | ||
|
||
// Print out status about an existing instance of the agent. | ||
func doStatus() { | ||
set := flag.NewFlagSet("status", flag.ExitOnError) | ||
configPath := set.String("config", getDefaultConfigPath(), "agent config path") | ||
set.Usage = func() { | ||
fmt.Fprintf(set.Output(), "Usage: signalfx-agent status [all | monitors | config | endpoints]\n\n"+ | ||
" The optional section arg can be one of the following:\n"+ | ||
" all - Dump everything available\n"+ | ||
" monitors - Show information about all active monitors\n"+ | ||
" config - Show the fully resolved configuration currently in use by the agent\n"+ | ||
" endpoints - Show the discovered endpoints available to discovery rules\n"+ | ||
" If no section arg is provided, a short summary of the agent is output\n\n") | ||
set.PrintDefaults() | ||
} | ||
|
||
_ = set.Parse(os.Args[2:]) | ||
|
||
log.SetLevel(log.ErrorLevel) | ||
|
||
var section string | ||
if len(set.Args()) == 1 { | ||
section = set.Args()[0] | ||
} else if len(set.Args()) > 1 { | ||
set.Usage() | ||
os.Exit(4) | ||
} | ||
|
||
status, err := core.Status(*configPath, section) | ||
if err != nil { | ||
fmt.Printf("Could not get status: %s\nAre you sure the agent is currently running?\n", err) | ||
os.Exit(1) | ||
} | ||
fmt.Print(string(status)) | ||
fmt.Println("") | ||
} | ||
|
||
// Print out agent self-description of config/metadata | ||
func doSelfDescribe() { | ||
log.SetOutput(os.Stderr) | ||
selfdescribe.JSON(os.Stdout) | ||
} | ||
|
||
var dpTapUsage = ` | ||
If no filters are specified, all datapoints will be output. | ||
Examples: | ||
Get all metrics that start with 'ps_' that have a plugin_instance dimension that starts with 'java': | ||
signalfx-agent tap-dps -metric 'ps_*' -dims '{plugin_instance: java*}' | ||
` | ||
|
||
func doDatapointTap() { | ||
set := flag.NewFlagSet("tap-dps", flag.ExitOnError) | ||
set.Usage = func() { | ||
fmt.Fprintf(set.Output(), "Usage of %s tap-dps:\n", os.Args[0]) | ||
set.PrintDefaults() | ||
fmt.Fprint(set.Output(), dpTapUsage) | ||
} | ||
|
||
configPath := set.String("config", getDefaultConfigPath(), "agent config path") | ||
metric := set.String("metric", "", "metric name filter string -- accepts globs") | ||
dims := set.String("dims", "", "dimension filter string in compact YAML map notation -- dimension values can be globbed") | ||
|
||
if err := set.Parse(os.Args[2:]); err != nil { | ||
set.Usage() | ||
os.Exit(1) | ||
} | ||
|
||
stream, err := core.StreamDatapoints(*configPath, *metric, *dims) | ||
if err != nil { | ||
fmt.Printf("Could not stream datapoints: %v", err) | ||
return | ||
} | ||
|
||
_, err = io.Copy(os.Stdout, stream) | ||
if err != io.EOF && err != nil { | ||
fmt.Printf("Error streaming datapoints: %v", err) | ||
} | ||
} | ||
|
||
// glog is a transitive dependency of the agent and puts a bunch of flags in | ||
// the flag package. We don't really ever need to have users override these, | ||
// but we would like ERROR messages going to stderr of the agent instead of to | ||
// a temporary file. | ||
func fixGlogFlags() { | ||
os.Args = os.Args[:1] | ||
flag.Parse() | ||
_ = flag.Set("logtostderr", "true") | ||
} | ||
|
||
// flags is used to store parsed flag values | ||
type flags struct { | ||
// configPath is a string flag for specifying the agent.yaml config file | ||
configPath string | ||
// service is a string flag used for starting, stopping, installing or | ||
// uninstalling the agent as a windows service (windows only) | ||
service string | ||
// logEvents is a bool flag for logging events to the Windows Application Event log. | ||
// This flag is only intended to be used when the agent is launched as a Windows Service. | ||
logEvents bool | ||
// version is a bool flag for printing the agent version string | ||
version bool | ||
// debug is a bool flag for printing debug level information | ||
debug bool | ||
} | ||
|
||
// getFlags retrieves flags passed to the agent at runtime and return them in a flags struct | ||
func getFlags() *flags { | ||
flags := &flags{} | ||
set := flag.NewFlagSet(os.Args[0], flag.ExitOnError) | ||
|
||
set.BoolVar(&flags.version, "version", false, "print agent version") | ||
set.StringVar(&flags.configPath, "config", getDefaultConfigPath(), "agent config path") | ||
set.BoolVar(&flags.debug, "debug", false, "print debugging output") | ||
|
||
// service is a windows only feature and should only be added to the flag set on windows | ||
if runtime.GOOS == windowsOS { | ||
set.StringVar(&flags.service, "service", "", "'start', 'stop', 'install' or 'uninstall' agent as a windows service. You may specify an alternate config file path with the -config flag when installing the service.") | ||
set.BoolVar(&flags.logEvents, "logEvents", false, "copy log events from the agent to the Windows Application Event Log. This is only used when the agent is deployed as a Windows service. The agent will write to stdout under all other deployment scenarios.") | ||
} | ||
|
||
// The set is configured to exit on errors so we don't need to check the | ||
// return value here. | ||
_ = set.Parse(os.Args[1:]) | ||
if len(set.Args()) > 0 { | ||
os.Stderr.WriteString("Non-flag parameters are not accepted\n") | ||
set.Usage() | ||
os.Exit(2) | ||
} | ||
fixGlogFlags() | ||
return flags | ||
} | ||
|
||
func runAgent(flags *flags, interruptCh chan os.Signal, exit chan struct{}) { | ||
var shutdown context.CancelFunc | ||
var shutdownComplete <-chan struct{} | ||
init := func() { | ||
logrus.Info("Starting up agent version " + constants.Version) | ||
shutdown, shutdownComplete = core.Startup(flags.configPath) | ||
} | ||
|
||
init() | ||
|
||
go func() { | ||
<-interruptCh | ||
logrus.Info("Interrupt signal received, stopping agent") | ||
shutdown() | ||
select { | ||
case <-shutdownComplete: | ||
break | ||
case <-time.After(10 * time.Second): | ||
logrus.Error("Shutdown timed out, forcing process down") | ||
break | ||
} | ||
close(exit) | ||
}() | ||
|
||
hupCh := make(chan os.Signal, 1) | ||
signal.Notify(hupCh, syscall.SIGHUP) | ||
go func() { | ||
for range hupCh { | ||
logrus.Info("Forcing agent reset") | ||
shutdown() | ||
<-shutdownComplete | ||
init() | ||
} | ||
}() | ||
|
||
<-exit | ||
} | ||
|
||
// Run is the primary entrypoint for the agent. It handles all of the command | ||
// line processing and starts up the agent. It will block until the agent | ||
// shuts down. | ||
func Run() { | ||
setVersionEnvvar() | ||
setCollectdVersionEnvvar() | ||
|
||
// set the agent version string | ||
core.VersionLine = fmt.Sprintf("agent-version: %s, collectd-version: %s\n", | ||
constants.Version, constants.CollectdVersion) | ||
|
||
// Make it so the symlink from agent-status to this binary invokes the | ||
// status command | ||
if strings.HasSuffix(os.Args[0], "agent-status") { | ||
os.Args = append([]string{os.Args[0], "status"}, os.Args[1:]...) | ||
} | ||
|
||
var firstArg string | ||
if len(os.Args) >= 2 { | ||
firstArg = os.Args[1] | ||
} | ||
|
||
switch firstArg { | ||
case "status": | ||
doStatus() | ||
case "selfdescribe": | ||
doSelfDescribe() | ||
case "tap-dps": | ||
doDatapointTap() | ||
default: | ||
if firstArg != "" && !strings.HasPrefix(firstArg, "-") { | ||
log.Errorf("Unknown subcommand '%s'", firstArg) | ||
os.Exit(127) | ||
} | ||
|
||
// fetch the commandline flags passed in at runtime | ||
flags := getFlags() | ||
|
||
if flags.debug { | ||
log.SetLevel(log.DebugLevel) | ||
} | ||
|
||
if flags.version { | ||
fmt.Printf(core.VersionLine) | ||
os.Exit(0) | ||
} | ||
|
||
// set up interrupt channel | ||
interruptCh := make(chan os.Signal, 1) | ||
signal.Notify(interruptCh, os.Interrupt) | ||
signal.Notify(interruptCh, syscall.SIGTERM) | ||
|
||
// create the exit channel that will block until agent is shutdown | ||
exitCh := make(chan struct{}, 1) | ||
// On windows we start the agent through the package github.com/kardianos/service. | ||
// The package provides hooks for installing and managing the agent as a windows service. | ||
runAgentPlatformSpecific(flags, interruptCh, exitCh) | ||
} | ||
|
||
os.Exit(0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
// +build !windows | ||
|
||
package main | ||
package agentmain | ||
|
||
import ( | ||
"os" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
// +build windows | ||
|
||
package main | ||
package agentmain | ||
|
||
import ( | ||
"os" | ||
|
Oops, something went wrong.