Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/cmd/grafana-agent-service/service.go
4093 views
1
package main
2
3
import (
4
"context"
5
"io"
6
"os/exec"
7
8
"github.com/go-kit/log"
9
"github.com/go-kit/log/level"
10
)
11
12
// serviceManager manages an individual binary.
13
type serviceManager struct {
14
log log.Logger
15
cfg serviceManagerConfig
16
}
17
18
// serviceManagerConfig configures a service.
19
type serviceManagerConfig struct {
20
// Path to the binary to run.
21
Path string
22
23
// Args of the binary to run, not including the command itself.
24
Args []string
25
26
// Dir specifies the working directory to run the binary from. If Dir is
27
// empty, the working directory of the current process is used.
28
Dir string
29
30
// Stdout and Stderr specify where the process' stdout and stderr will be
31
// connected.
32
//
33
// If Stdout or Stderr are nil, they will default to os.DevNull.
34
Stdout, Stderr io.Writer
35
}
36
37
// newServiceManager creates a new, unstarted serviceManager. Call
38
// [service.Run] to start the serviceManager.
39
//
40
// Logs from the serviceManager will be sent to w. Logs from the managed
41
// service will be written to cfg.Stdout and cfg.Stderr as appropriate.
42
func newServiceManager(l log.Logger, cfg serviceManagerConfig) *serviceManager {
43
if l == nil {
44
l = log.NewNopLogger()
45
}
46
47
return &serviceManager{
48
log: l,
49
cfg: cfg,
50
}
51
}
52
53
// Run starts the serviceManager. The binary associated with the serviceManager
54
// will be run until the provided context is canceled or the binary exits.
55
//
56
// Intermediate restarts will increase with an exponential backoff, which
57
// resets if the binary has been running for longer than the maximum
58
// exponential backoff period.
59
func (svc *serviceManager) Run(ctx context.Context) {
60
cmd := svc.buildCommand(ctx)
61
62
level.Info(svc.log).Log("msg", "starting program", "command", cmd.String())
63
err := cmd.Run()
64
65
// Handle the context being canceled before processing whether cmd.Run
66
// exited with an error.
67
if ctx.Err() != nil {
68
return
69
}
70
71
exitCode := cmd.ProcessState.ExitCode()
72
73
if err != nil {
74
level.Error(svc.log).Log("msg", "service exited with error", "err", err, "exit_code", exitCode)
75
} else {
76
level.Info(svc.log).Log("msg", "service exited", "exit_code", exitCode)
77
}
78
}
79
80
func (svc *serviceManager) buildCommand(ctx context.Context) *exec.Cmd {
81
cmd := exec.CommandContext(ctx, svc.cfg.Path, svc.cfg.Args...)
82
cmd.Dir = svc.cfg.Dir
83
cmd.Stdout = svc.cfg.Stdout
84
cmd.Stderr = svc.cfg.Stderr
85
return cmd
86
}
87
88