// Service setup. // Define service config. // Create the service. // Setup the logger. // Handle service controls (optional). // Run the service. func main() { svcFlag := flag.String("service", "", "Control the system service.") flag.Parse() if !service.Interactive() { root, _ := osext.ExecutableFolder() f, err := os.OpenFile(root+"/output.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatal(err) } defer f.Close() log.SetOutput(f) } svcConfig := &service.Config{ Name: "FPL Checker", DisplayName: "FPL Checker", Description: "Free Post Code Lottery daily winner checker", } prg := &program{} s, err := service.New(prg, svcConfig) if err != nil { log.Fatal(err) } errs := make(chan error, 5) logger, err = s.Logger(errs) if err != nil { log.Fatal(err) } go func() { for { err := <-errs if err != nil { log.Print(err) } } }() if len(*svcFlag) != 0 { err := service.Control(s, *svcFlag) if err != nil { log.Printf("Valid actions: %q\n", service.ControlAction) log.Fatal(err) } return } err = s.Run() if err != nil { logger.Error(err) } }
func (p *program) Stop(s service.Service) error { close(p.exit) logger.Info("Stopping ", p.DisplayName) if p.cmd.ProcessState.Exited() == false { p.cmd.Process.Kill() } if service.Interactive() { os.Exit(0) } return nil }
func (p *program) Start(s service.Service) error { if service.Interactive() { logger.Info("Running in terminal.") } else { logger.Info("Running under service manager.") } p.exit = make(chan struct{}) // Start should not block. Do the actual work async. go p.run() return nil }
func (p *program) run() { logger.Info("Starting ", p.DisplayName) defer func() { if service.Interactive() { p.Stop(p.service) } else { p.service.Stop() } }() if p.Stderr != "" { f, err := os.OpenFile(p.Stderr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) if err != nil { logger.Warningf("Failed to open std err %q: %v", p.Stderr, err) return } defer f.Close() p.cmd.Stderr = f } if p.Stdout != "" { f, err := os.OpenFile(p.Stdout, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777) if err != nil { logger.Warningf("Failed to open std out %q: %v", p.Stdout, err) return } defer f.Close() p.cmd.Stdout = f } err := p.cmd.Run() if err != nil { logger.Warningf("Error running: %v", err) } return }
func reloadLoop(stop chan struct{}, s service.Service) { defer func() { if service.Interactive() { os.Exit(0) } return }() reload := make(chan bool, 1) reload <- true for <-reload { reload <- false flag.Usage = func() { usageExit(0) } flag.Parse() args := flag.Args() var inputFilters []string if *fInputFilters != "" { inputFilter := strings.TrimSpace(*fInputFilters) inputFilters = strings.Split(":"+inputFilter+":", ":") } var outputFilters []string if *fOutputFilters != "" { outputFilter := strings.TrimSpace(*fOutputFilters) outputFilters = strings.Split(":"+outputFilter+":", ":") } if len(args) > 0 { switch args[0] { case "version": v := fmt.Sprintf("Telegraf - version %s", version) fmt.Println(v) return case "config": config.PrintSampleConfig(inputFilters, outputFilters) return } } // switch for flags which just do something and exit immediately switch { case *fOutputList: fmt.Println("Available Output Plugins:") for k, _ := range outputs.Outputs { fmt.Printf(" %s\n", k) } return case *fInputList: fmt.Println("Available Input Plugins:") for k, _ := range inputs.Inputs { fmt.Printf(" %s\n", k) } return case *fVersion: v := fmt.Sprintf("Telegraf - version %s", version) fmt.Println(v) return case *fSampleConfig: config.PrintSampleConfig(inputFilters, outputFilters) return case *fUsage != "": if err := config.PrintInputConfig(*fUsage); err != nil { if err2 := config.PrintOutputConfig(*fUsage); err2 != nil { log.Fatalf("%s and %s", err, err2) } } return case *fService != "" && runtime.GOOS == "windows": if *fConfig != "" { (*svcConfig).Arguments = []string{"-config", *fConfig} } err := service.Control(s, *fService) if err != nil { log.Fatal(err) } return } // If no other options are specified, load the config file and run. c := config.NewConfig() c.OutputFilters = outputFilters c.InputFilters = inputFilters err := c.LoadConfig(*fConfig) if err != nil { fmt.Println(err) os.Exit(1) } if *fConfigDirectory != "" { err = c.LoadDirectory(*fConfigDirectory) if err != nil { log.Fatal(err) } } if len(c.Outputs) == 0 { log.Fatalf("Error: no outputs found, did you provide a valid config file?") } if len(c.Inputs) == 0 { log.Fatalf("Error: no inputs found, did you provide a valid config file?") } ag, err := agent.NewAgent(c) if err != nil { log.Fatal(err) } if *fDebug { ag.Config.Agent.Debug = true } if *fQuiet { ag.Config.Agent.Quiet = true } if *fTest { err = ag.Test() if err != nil { log.Fatal(err) } return } err = ag.Connect() if err != nil { log.Fatal(err) } shutdown := make(chan struct{}) signals := make(chan os.Signal) signal.Notify(signals, os.Interrupt, syscall.SIGHUP) go func() { select { case sig := <-signals: if sig == os.Interrupt { close(shutdown) } if sig == syscall.SIGHUP { log.Printf("Reloading Telegraf config\n") <-reload reload <- true close(shutdown) } case <-stop: close(shutdown) } }() log.Printf("Starting Telegraf (version %s)\n", version) log.Printf("Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) log.Printf("Loaded inputs: %s", strings.Join(c.InputNames(), " ")) log.Printf("Tags enabled: %s", c.ListTags()) if *fPidfile != "" { f, err := os.Create(*fPidfile) if err != nil { log.Fatalf("Unable to create pidfile: %s", err) } fmt.Fprintf(f, "%d\n", os.Getpid()) f.Close() } ag.Run(shutdown) } }
func reloadLoop(stop chan struct{}, s service.Service) { defer func() { if service.Interactive() { os.Exit(0) } return }() reload := make(chan bool, 1) reload <- true for <-reload { reload <- false flag.Parse() args := flag.Args() var inputFilters []string if *fInputFilters != "" { inputFilter := strings.TrimSpace(*fInputFilters) inputFilters = strings.Split(":"+inputFilter+":", ":") } var outputFilters []string if *fOutputFilters != "" { outputFilter := strings.TrimSpace(*fOutputFilters) outputFilters = strings.Split(":"+outputFilter+":", ":") } var aggregatorFilters []string if *fAggregatorFilters != "" { aggregatorFilter := strings.TrimSpace(*fAggregatorFilters) aggregatorFilters = strings.Split(":"+aggregatorFilter+":", ":") } var processorFilters []string if *fProcessorFilters != "" { processorFilter := strings.TrimSpace(*fProcessorFilters) processorFilters = strings.Split(":"+processorFilter+":", ":") } if len(args) > 0 { switch args[0] { case "version": fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit) return case "config": config.PrintSampleConfig( inputFilters, outputFilters, aggregatorFilters, processorFilters, ) return } } // switch for flags which just do something and exit immediately switch { case *fOutputList: fmt.Println("Available Output Plugins:") for k, _ := range outputs.Outputs { fmt.Printf(" %s\n", k) } return case *fInputList: fmt.Println("Available Input Plugins:") for k, _ := range inputs.Inputs { fmt.Printf(" %s\n", k) } return case *fVersion: fmt.Printf("Telegraf v%s (git: %s %s)\n", version, branch, commit) return case *fSampleConfig: config.PrintSampleConfig( inputFilters, outputFilters, aggregatorFilters, processorFilters, ) return case *fUsage != "": if err := config.PrintInputConfig(*fUsage); err != nil { if err2 := config.PrintOutputConfig(*fUsage); err2 != nil { log.Fatalf("E! %s and %s", err, err2) } } return } // If no other options are specified, load the config file and run. c := config.NewConfig() c.OutputFilters = outputFilters c.InputFilters = inputFilters err := c.LoadConfig(*fConfig) if err != nil { log.Fatal("E! " + err.Error()) } if *fConfigDirectory != "" { err = c.LoadDirectory(*fConfigDirectory) if err != nil { log.Fatal("E! " + err.Error()) } } if len(c.Outputs) == 0 { log.Fatalf("E! Error: no outputs found, did you provide a valid config file?") } if len(c.Inputs) == 0 { log.Fatalf("E! Error: no inputs found, did you provide a valid config file?") } ag, err := agent.NewAgent(c) if err != nil { log.Fatal("E! " + err.Error()) } // Setup logging logger.SetupLogging( ag.Config.Agent.Debug || *fDebug, ag.Config.Agent.Quiet || *fQuiet, ag.Config.Agent.Logfile, ) if *fTest { err = ag.Test() if err != nil { log.Fatal("E! " + err.Error()) } return } err = ag.Connect() if err != nil { log.Fatal("E! " + err.Error()) } shutdown := make(chan struct{}) signals := make(chan os.Signal) signal.Notify(signals, os.Interrupt, syscall.SIGHUP) go func() { select { case sig := <-signals: if sig == os.Interrupt { close(shutdown) } if sig == syscall.SIGHUP { log.Printf("I! Reloading Telegraf config\n") <-reload reload <- true close(shutdown) } case <-stop: close(shutdown) } }() log.Printf("I! Starting Telegraf (version %s)\n", version) log.Printf("I! Loaded outputs: %s", strings.Join(c.OutputNames(), " ")) log.Printf("I! Loaded inputs: %s", strings.Join(c.InputNames(), " ")) log.Printf("I! Tags enabled: %s", c.ListTags()) if *fPidfile != "" { f, err := os.Create(*fPidfile) if err != nil { log.Fatalf("E! Unable to create pidfile: %s", err) } fmt.Fprintf(f, "%d\n", os.Getpid()) f.Close() } ag.Run(shutdown) } }
// program start func main() { var err error sconf := service.Config{ Name: "BabelPoxy", DisplayName: "Babel Proxy", Description: "babelproxy converts RESTful calls into Babel calls.", } // Parse flags from command-line flag.Parse() // Parser flags from config flagcfg.AddDefaults() flagcfg.Parse() // Parse flags from environment (using github.com/facebookgo/flagenv) flagenv.Prefix = "BABELPROXY_" flagenv.Parse() // show help if asked if help { fmt.Fprintln(os.Stderr, `Usage of babelproxy: babelproxy [options] <filepatterns> "For the faasti RESTafarians! (Feel no way, we maas.)" Example: babelproxy *.babel Options include:`) flag.PrintDefaults() fmt.Fprintln(os.Stderr, ` All of the options can be overridden in the configuration file. To override the location of the configuration file, set the BABELPROXY_CONFIG environment variable. When running as a service, all options must be specified in the configuration file or environment variables.`) return } // show version if asked if ver { fmt.Printf("babelproxy Version %s\n", BABELPROXY_VERSION) return } // default the pubaddr if strings.TrimSpace(conf.PubAddr) == "" { conf.PubAddr = conf.RestAddr } // handle kill signals go func() { // setup cpu profiling if desired var f io.WriteCloser var err error if conf.CpuProfile != "" { f, err = os.Create(conf.CpuProfile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) } // Set up channel on which to send signal notifications. // We must use a buffered channel or risk missing the signal // if we're not ready to receive when the signal is sent. c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) // Block until a signal is received. s := <-c log.Print("Got signal ", s, ", canceling work") if conf.CpuProfile != "" { log.Print("Writing CPU profile to ", conf.CpuProfile) pprof.StopCPUProfile() f.Close() } // write memory profile if configured if conf.MemProfile != "" { f, err := os.Create(conf.MemProfile) if err != nil { log.Print(err) } else { log.Print("Writing memory profile to ", conf.MemProfile) pprof.WriteHeapProfile(f) f.Close() } } os.Exit(0) }() // setup number of CPUs runtime.GOMAXPROCS(conf.Cpus) // set working directory if conf.WorkingDir != "" { err = os.Chdir(conf.WorkingDir) if err != nil { log.Fatal(err) } } // override configured arguments (file list) with command line if flag.NArg() > 0 { conf.Args = flag.Args() } var i svcImpl svcBroxy, err = service.New(&i, &sconf) if err != nil { log.Fatal(err) } /* svcLogger, err = svcBroxy.Logger(nil) if err != nil { log.Fatal(err) } */ if control != "" { err = service.Control(svcBroxy, control) if err != nil { log.Fatal(err) } return } if service.Interactive() { i.doWork() } else { err = svcBroxy.Run() if err != nil { //svcLogger.Error(err.Error()) log.Println(err) } } }