Skip to content

Commit 35749fb

Browse files
committed
Initial commit.
0 parents  commit 35749fb

File tree

7 files changed

+169
-0
lines changed

7 files changed

+169
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
loader
2+
test

Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
go build loader.go
3+
go build test.go
4+
.PHONY: all
5+
.DEFAULT: all

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Go Spawn & Debug Process
2+
This is a small project to demonstrate how to spawn multiple processes from a Go program and have the Go program write their `stdout` and `stderr` lines to a log file.
3+
4+
In this example, we have `test` and `loader` Go programs.
5+
6+
The `test` program outputs a random string from the `messages` variable each second to `stdout`. This is just used as a demo program.
7+
8+
The `loader` program runs the `test` program five times and outputs their `stdout` and `stderr` pipes to a log file in the `logs/` directory (e.g. `logs/<pid>.log`).
9+
10+
## Building
11+
You may use `make` via Makefile to build everything easily. Otherwise, you may use `go build loader.go` and `go build test.go` to build the Go programs.
12+
13+
## Running
14+
Simply run the `loader` executable to test.
15+
16+
```bash
17+
./loader
18+
```
19+
20+
**Note** - The `remove_logs.sh` file is ran on each loader start. This Bash script simply removes all log files in the `logs/` directory so we start off from a clean slate and the loader ignores any errors from executing the file.
21+
22+
## Credits
23+
* [Christian Deacon](https://github.com/gamemann)

loader.go

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"os/signal"
9+
"syscall"
10+
)
11+
12+
type TestProcess struct {
13+
Process *exec.Cmd
14+
Stdout *bufio.Writer
15+
Stderr *bufio.Writer
16+
}
17+
18+
const RMLOGS_EXEC = "./remove_logs.sh"
19+
const EXEC = "./test"
20+
const NUM_PROCESSES = 5
21+
22+
func main() {
23+
// Remove logs by using shell script.
24+
rmLogs := exec.Command(RMLOGS_EXEC)
25+
26+
err := rmLogs.Run()
27+
28+
if err != nil {
29+
fmt.Println("Failed to remove logs via shell script.")
30+
fmt.Println(err)
31+
}
32+
33+
var processes []*TestProcess
34+
35+
for i := 0; i < NUM_PROCESSES; i++ {
36+
process := exec.Command(EXEC)
37+
38+
stdoutPipe, _ := process.StdoutPipe()
39+
stderrPipe, _ := process.StderrPipe()
40+
41+
err := process.Start()
42+
43+
if err != nil {
44+
fmt.Printf("[%d] Error creating process.\n", i)
45+
fmt.Println(err)
46+
47+
continue
48+
}
49+
50+
if process.Process == nil {
51+
fmt.Printf("[%d] Could not find process.\n", process.Process.Pid)
52+
53+
continue
54+
}
55+
56+
// Create log file.
57+
fileName := fmt.Sprintf("logs/%d.log", process.Process.Pid)
58+
logFile, err := os.Create(fileName)
59+
60+
if err != nil {
61+
fmt.Printf("[%d] Error creating log file :: %s.\n", process.Process.Pid, fileName)
62+
63+
continue
64+
}
65+
66+
stdoutWriter := bufio.NewWriter(logFile)
67+
stderrWriter := bufio.NewWriter(logFile)
68+
69+
// Create goroutines to capture stdout and stderr output and write them our log files.
70+
go func() {
71+
scanner := bufio.NewScanner(stdoutPipe)
72+
for scanner.Scan() {
73+
line := scanner.Text()
74+
stdoutWriter.WriteString(line + "\n")
75+
stdoutWriter.Flush()
76+
}
77+
}()
78+
79+
go func() {
80+
scanner := bufio.NewScanner(stderrPipe)
81+
for scanner.Scan() {
82+
line := scanner.Text()
83+
stderrWriter.WriteString(line + "\n")
84+
stderrWriter.Flush()
85+
}
86+
}()
87+
88+
processes = append(processes, &TestProcess{Process: process, Stdout: stdoutWriter, Stderr: stderrWriter})
89+
}
90+
91+
fmt.Println("Started loader. Check logs/ directory for outputs.")
92+
93+
sigc := make(chan os.Signal, 1)
94+
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
95+
96+
<-sigc
97+
98+
os.Exit(0)
99+
}

logs/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

remove_logs.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
rm -f logs/*.log

test.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
"os"
7+
"os/signal"
8+
"syscall"
9+
"time"
10+
)
11+
12+
var messages = []string{
13+
"This is a test message",
14+
"Another test message.",
15+
"Or ANOTHER test message.",
16+
"Or yet ANOTHER test message!!!!",
17+
}
18+
19+
func Repeat() {
20+
for range time.Tick(time.Second * 1) {
21+
fmt.Println(messages[rand.Intn(len(messages))])
22+
}
23+
}
24+
25+
func main() {
26+
// Repeat.
27+
go Repeat()
28+
29+
sigc := make(chan os.Signal, 1)
30+
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
31+
32+
<-sigc
33+
34+
os.Exit(0)
35+
}

0 commit comments

Comments
 (0)